在ICollection的属性上拦截NHibernate持久化操作(许多关联)

时间:2012-02-08 18:14:18

标签: hibernate nhibernate nhibernate-mapping hibernate-mapping

我想拦截对集合属性的持久性操作,自己决定它是否可以与数据库同步,并在决定一次性地对所有集合而不是每个元素发生持久性时调用过程。

怎么做?

这些集合属性通常映射为一对多或多对多关联。所以,当我们有这样的事情时:

myEntity.List.Add(new Item());
myEntity.List.Add(new Item());
...
session.Save(myEntity);

对于具有两个类(实体)和单向多对多关联的映射,我希望只发生两个sql语句:INSERT INTO和一个期望接收的PROCEDURE CALL以逗号分隔的值列表,它是上述List集合中的键值。密钥集合只能保存在此系统上,调用带有值列表(csv)的过程。

这种定制是否可行?

2 个答案:

答案 0 :(得分:1)

好吧,我采用了一个实现NHibernate Listeners的解决方案,所以我有一个像这样的监听器:

public class CustomSaveUpdateEventListener : IPostInsertEventListener, IPostUpdateEventListener {

    private void ScheduleToCommit(AbstractPostDatabaseOperationEvent @event) {
        // Some filter
        if (@event.Entity.GetType().FullName.Equals(MY_ENTITY_TO_INTERCEPTS) {
            object o = @event.Entity;

            // Some logic...
            // ...
            // ...

            IQuery namedQuery = @event.Session.GetNamedSQLQuery(MY_NAMED_QUERY);
            //namedQuery.SetParameter(...); // <== You can set parameters
            //namedQuery.ExecuteUpdate(); // <== DO NOT EXCEUTE HERE, this launches more events recursively and can generate stackoverflow

            @event.Session.ActionQueue.RegisterProcess(new MyActionBeforeCommit(@event, namedQuery).SaveValuesOperation);
            }
        }
    }

    public void OnPostInsert(PostInsertEvent @event) {
        ScheduleToCommit(@event);
    }


    public void OnPostUpdate(PostUpdateEvent @event) {
        ScheduleToCommit(@event);
    }
}

我的对象MyActionBeforeCommit()计划仅在提交事务时运行。所以,在我的“未来行动”中,我有:

public class MyActionBeforeCommit {
    private AbstractPostDatabaseOperationEvent e;

    private IQuery query;

    public MyActionBeforeCommit(AbstractPostDatabaseOperationEvent e, IQuery query) {
        this.e = e;
        this.query = query;
    }

    public void SaveValuesOperation() {
        // Here your query will be executed only when a transation is commited, if 
        // it's rolledback this won't be executed
        query.ExecuteUpdate(); 
    }
}

最后我们需要在NHibernate配置上注册新的监听器,如:

Configuration.SetListener(ListenerType.PostInsert, new    CustomSaveUpdateEventListener());
Configuration.SetListener(ListenerType.PostUpdate, new CustomSaveUpdateEventListener());

而且效果很好。这是一个非常好的NHibernate功能,非常强大。

答案 1 :(得分:0)

我等了一会儿回应,因为我知道一种可能的方法,但从来没有自己做过。

听起来你需要编写一个自定义的NHibernate“方言”。有一些指导原则here,以及如何做到这一点。

您没有提到您使用的数据库系统,但您的出发点显然是采用该系统的方言并找到您应该自定义的位置。

NHibernate完全支持Overriding Dialects。如果这对您不起作用,您甚至可能需要查看自定义AbstractEntityPersister,但我不知道如何使用配置文件条目。

您可以找到NHibernate 3.2来源here

完全不同的方法可以是将标准NHibernate持久性用于本地数据库,例如sql-server CE,并执行“真正”持久性的同步脚本。