2009-11-17 2 views
3

Я реализую пользовательский EventListener для сохранения информации аудита в NHibernate.NHibernate EventListeners - получение значения свойства сохраняемого объекта

В настоящее время я расширяю DefaultSaveOrUpdateEventListener, переопределяя PerformSaveOrUpdate, просматривая свойства каждого объекта и сохраняя их в другом месте.

Это работает с простыми свойствами, но сбой при каскаде - сохранение отношения «один ко многим».

Если взять следующие объекты:

[ActiveRecord] 
public class Child 
{ 
    [PrimaryKey(PrimaryKeyType.GuidComb)] 
    public Guid Id { get; set; } 

    [BelongsTo] 
    public Parent Parent { get; set; } 
} 

[ActiveRecord] 
public class Parent 
{ 
    [PrimaryKey(PrimaryKeyType.GuidComb)] 
    public Guid Id { get; set; } 

    [HasMany(Cascade = ManyRelationCascadeEnum.SaveUpdate)] 
    public IList<Child> Children { get; set; } 
} 

, а затем сохранить родитель с ребенком:

ActiveRecordMediator<Parent>.Save(new Parent 
{ 
    Children = new List<Child> 
    { 
     new Child() 
    } 
}); 

Ребенок получит правильный родитель, возложенный на него, когда его сохраняется в базу данных но свойство «Родительское» для ребенка равно null, когда вызывается мой EventListener.

Как я могу получить значение, которое на самом деле будет сохраняться в базе данных в этом случае?

[EDIT] Недавно я смотрел, как это работает, подключив каскад и увидев, что еще было спасено в то время, но это кажется ужасно ненадежным, и я бы предпочел получить данные из NHibernate, поэтому я знаю, что это соответствует базе данных.

ответ

2

Я не знаю, как вы можете сделать это с ActiveRecord, но он должен делать с механизмом, в котором NHibernate сохраняется родитель/потомок.

Сохранение дочернего каскада перед сохранением родительского элемента в NHibernate осуществляется в зависимости от того, какой конец отношения отмечен как «inverse = true», а дочерний элемент должен иметь атрибут «not-null = true» на элемент (который определяет, какой конец владеет отношениями). Это сделает так, чтобы Ребенок управлял состоянием отношений.

Затем вы можете просто сохранить ребенка, и родитель будет обновлен с соответствующей информацией. Это будет генерировать один оператор INSERT, а не INSERT AND UPDATE, который вы, вероятно, видите сейчас.Не уверен, что это решает вашу проблему, но я считаю, что проблема, с которой вы сталкиваетесь, связана с этим поведением. Вы можете прочитать по этой ссылке:

https://www.hibernate.org/hib_docs/nhibernate/html/example-parentchild.html

+0

Спасибо - я не уверен, что решает мою актуальную проблему (Child.Parent по-прежнему равен нулю в момент, когда мой слушатель выполняется), но по крайней мере я понимаю случай, когда мой код делает неприятные взломы для сохранения каскада, и я исправил ошибку , –

0

Я вижу, что вы используете Castle ActiveRecord. Я тоже экспериментировал с этим.

В нем есть странность, потому что в коде, который вы предоставили, свойство Parent дочернего объекта будет установлено только после того, как ваш материал будет сохранен в базе данных. До тех пор его значение будет равно нулю. (Я не знаю, является ли это поведение специфичным для ActiveRecord, или также NHibernate.)

Возможно, если вы вручную назначите свойства родителя объектов Child, оно будет работать.

var parent = new Parent(); 
var child = new Child() 
{ 
    Parent = parent 
}; 
parent.Children.Add(child); 

ActiveRecordMediator<Parent>.Save(child); 
ActiveRecordMediator<Parent>.Save(parent); 

Возможно, заказ, в котором вы сохраняете сущности, также должен что-то сделать с этим вопросом.

+0

Да и нет. Он работает, но он работает, потому что NHibernate не выполняет каскадную экономию - разработчик это делает. К сожалению, это означало бы отключение каскадного сохранения, что довольно фундаментально для достойной ORM. Спасибо за предложение. –

+0

На самом деле, сохранение каскада работает хорошо, но есть проблема, что ребенок не получает свой родительский набор, пока он не будет сохранен. (Или, по крайней мере, так было в ActiveRecord в прошлый раз, когда я пробовал.) Ваш слушатель событий получает детей до того, как это произойдет. – Venemo

0

Я не использую ActiveRecord, я использую NHibernate вместо так что я буду считать, что они обращаются родитель-потомок таким же образом (https://www.hibernate.org/hib_docs/nhibernate/html/example-parentchild.html)

Что произойдет, если вы оставите ОРМ, чтобы управлять ссылку на родительский объект (путем установки Inverse = true в атрибуте HasMany)?

[ActiveRecord] 
public class Parent 
{ 
    [PrimaryKey(PrimaryKeyType.GuidComb)] 
    public Guid Id { get; set; } 

    [HasMany(Cascade = ManyRelationCascadeEnum.SaveUpdate, Inverse=true)] 
    public IList<Child> Children { get; set; } 
} 
+0

Привет, Бен. Увы, насколько я могу судить, это не имеет никакого значения. –

Смежные вопросы