我正在使用几个自定义实体状态更改侦听器来实现NHibernate 3.2:PreDelete,Delete和PostDelete。 DeleteEventListener是通过从DefaultDeleteEventListener继承自定义类型来定义的,但其他人只是实现了IEventListener接口。
CustomDeleteEventListener的主体如下:
protected override void DeleteEntity(IEventSource session, object entity, EntityEntry entityEntry, bool isCascadeDeleteEnabled, IEntityPersister persister, ISet transientEntities)
{
if (entity is BaseEntity)
HandleEntityAssociations(session, (BaseEntity)entity);
if (entity is ISoftDeletable)
{
var e = (ISoftDeletable)entity;
Utility.SetTrackingInfo(e as BaseModel);
e.Deleted = true;
CascadeBeforeDelete(session, persister, entity, entityEntry, transientEntities);
CascadeAfterDelete(session, persister, entity, transientEntities);
}
else
{
base.DeleteEntity(session, entity, entityEntry, isCascadeDeleteEnabled, persister, transientEntities);
}
}
在我的测试中,我发现OnDelete()
监听器总是在 OnPreDelete()
和OnPostDelete()
监听器之前被称为,而Pre和如果未调用base.DeleteEntity()
,帖子监听器将永远不会触发。这对我没有任何意义 - 我希望订单是:OnPreDelete()
,OnDelete()
,OnPostDelete()
。
当我检查了callstack时,我注意到OnDeleteEvent()
是在调用FireDelete()
后立即调用ISession.Delete()
的基础调用触发的,OnPreDeleteEvent()
被OnFlush()
触发了OnDeleteEvent()
的听众 - 与class popupframe extends JFrame{
JMenuItem copy;
JMenuItem paste;
JTextArea textarea = new JTextArea();
JPopupMenu pop;
popupframe(){
Container cpane = getContentPane();
setSize(300 , 300);
setLocation(300, 300);
setTitle("Test");
JPopupMenu pop = new JPopupMenu();
copy = new JMenuItem("copy");
paste = new JMenuItem("paste");
textarea = new JTextArea("something goes here", 5, 5);
pop.add(copy);
pop.add(paste);
PopupListener popuplistener = new PopupListener();
textarea.addMouseListener(popuplistener);
}
class PopupListener extends MouseAdapter{
public void MousePressed(MouseEvent e){
popit(e);
}
public void MouseReleased(MouseEvent e){
popit(e);
}
private void popit(MouseEvent e){
if(e.isPopupTrigger()){
pop.show(e.getComponent(), e.getX(), e.getY());
}
}
}
}
的通话完全断开连接。
这些听众几乎没有文档,只有少数博客使用它们来实现这一点。有谁知道这些在NHibernate 3.2中是如何工作的,为什么我看到了我的行为?
答案 0 :(得分:4)
据我了解,OnDelete
,OnUpdate
,...用于执行验证等操作,或修改要删除,更新,插入的实际实体。这种情况几乎发生在管道的开始,例如, "NHibernate interceptor magic tricks, pt. 4"
当发生删除时,NHibernate所做的第一件事就是调用
IInterceptor.OnDelete(object entity, object id, object[] state, string[] propertyNames, IType[] types)
方法。它不提供任何流控制,只是在调度实际删除操作之前由默认IDeleteEventListener
调用。
另请参阅该博客系列的其他部分以获取更多信息。
PreDelete
和PostDelete
事件侦听器在DeleteAction
中调用,NHibernate IPreUpdateEventListener & IPreInsertEventListener本身由DefaultDeleteEventListener
(即您派生的类)创建{ {1}}方法,并添加到会话的操作队列中。因此,在DeleteEntity
调用之后调用。
DeleteEventListener
事件恰好在发出实际命令之前发生。此时,通过修改实体本身强制更改命令为时已晚,尽管您可以使用命令的参数(并确保将这些更改应用于相应的实体的字段) ,或使用子会话执行其他操作(例如,插入审核记录)。从任何这些Pre...
侦听器返回true
将否决更改,返回Pre...
将导致执行它。
您可能需要阅读此博文:{{3}}。它涉及更新和插入侦听器,但对于删除,推理将类似。
这些允许我们在将更新/插入发送到数据库之前执行我们的自定义逻辑。从表面上看,它似乎是一项微不足道的任务,但在使用它们时我们需要考虑一些细微之处。
那些钩子在处理管道中运行得非常晚,这是使它们如此有用的部分,但是因为它们运行得太晚,当我们使用它们时,我们必须知道我们正在对它们做什么以及它是如何做的影响了应用程序的其余部分。
看来"非常迟到"的意思是:
一旦事件监听器完成运行就会执行的ADO.Net命令。
由于NHibernate的根源在于Java Hibernate版本,该版本具有相同类型的侦听器和事件,这是有关此主题的更多官方文档的另一个潜在信息来源。