简体   繁体   English

NHibernate级联删除

[英]NHibernate cascade delete

Let me begin with showing the mapping: 让我首先展示映射:

Parent: 家长:

<bag name="Communicatiekanalen" table="COMMUNICATIEKANAAL" inverse="true" cascade="delete" lazy="true" >
        <key column="SEK_PROFIEL"/>
        <one-to-many class="Crm.Hibernate.Communicatiekanaal,Crm.Hibernate" />
</bag>

Child: 儿童:

<many-to-one name="SekProfiel" column="SEK_PROFIEL" class="Crm.Hibernate.Profiel,Crm.Hibernate" />

In other words: a profile can have many communication channels. 换句话说:配置文件可以有许多通信通道。

On the UI (user-interface [ASP.NET Webforms] ) the following event is fired (deleting a profile with communication channels attached to it) : 在UI(用户界面[ASP.NET Webforms] )上触发以下事件(删除附加了通信通道的配置文件):

    var profielDao = CrmConfiguration.GetDaoFactory().GetProfielDao();
    var profiel = profielDao.GetById(2194, true); //lets say '2194' is an ID that exists
    profielDao.Delete(profiel);

(the DaoFactory is located in one project file and the UI is an ASP.NET Website) (DaoFactory位于一个项目文件中,UI是一个ASP.NET网站)

This code works. 这段代码有效。

IMPORTANT: the code is using the NHibernate 'open-session-in-view' pattern. 重要提示:代码使用的是NHibernate的“open-session-in-view”模式。

I have a service implementation that fires the same code (deleting a profile with communication channels). 我有一个服务实现,触发相同的代码(删除具有通信通道的配置文件)。 Some code... 一些代码......

            var daof = CrmConfiguration.GetDaoFactory();
            CrmSettings.Instance.UserID = user;
            var profielDao = daof.GetProfielDao();

            profielDao.BeginTransaction();
            var profiel = profielDao.GetById(CrmEntitiesToHibernate.ParseStringToId(profileId), true);
            profielDao.Delete(profiel);
            profielDao.EndTransaction();

Where 'EndTransaction()' does a 'commit'. 'EndTransaction()'执行“提交”的位置。 I test this code with an 'unit test': 我用'单元测试'测试了这段代码:

    [TestMethod]
    public void TestDeleteProfile()
    {
        //Getting a valid NEW profile
        var profile = GetSecundaryProfile();
        //Adding a communication channel to the profile
        CrmClient.AddCommunicationChannelForProfile(GetPlainCommunicationChannel(), profile.Id, CurrentUserId);
        //Calling the 'delete profile' method on the service --> FAIL - no cascade
        CrmClient.DeleteProfile(profile.Id, CurrentUserId);
    }

This code fails. 此代码失败。 The following error is bugging me: 以下错误让我烦恼:

The DELETE statement conflicted with the REFERENCE constraint "R2_PROFIEL". DELETE语句与REFERENCE约束“R2_PROFIEL”冲突。 The conflict occurred in database "CRM_ontw", table "dbo.COMMUNICATIEKANAAL", column 'SEK_PROFIEL'. 冲突发生在数据库“CRM_ontw”,表“dbo.COMMUNICATIEKANAAL”,列“SEK_PROFIEL”中。 The statement has been terminated. 该语句已终止。

This means that the cascade didn't happen at all. 这意味着级联根本没有发生。 Executed from the UI it works , but when fired from the ' service implementation ', it fails . 从它工作UI执行,但是当从“ 服务实现 ”触发时,它失败了 Any ideas or suggestions that could help me? 任何可以帮助我的想法或建议?

Thanks in advance 提前致谢


Edit: the following generic code delete's an object 编辑:以下通用代码删除一个对象

    public void Delete(T entity)
    {
        try
        {
            OnDelete(entity);
        }
        catch (Exception)
        {
            SessionManager.Instance.RollbackTransactionOn(SessionFactoryConfigPath);
            throw;
        }
        session.Delete(entity);
    }

Setting the all-delete-orphan doesn't fix the problem. 设置all-delete-orphan不能解决问题。

I've found the problem. 我发现了这个问题。 The NHibernate 'open-session-in-view' pattern closes the session after commiting the changes to the database (so when the requests ends, the sessions gets closed): NHibernate的“open-session-in-view”模式在将更改提交到数据库后关闭会话(因此当请求结束时,会话将关闭):

        finally
        {
            // No matter what happens, make sure all the sessions get closed
            foreach (SessionFactoryElement sessionFactorySettings in openSessionInViewSection.SessionFactories)
            {
                SessionManager.Instance.CloseSessionOn(sessionFactorySettings.FactoryConfigPath);
            }
        }

But my EndTransaction() implementation on the service side didn't. 但是我在服务端的EndTransaction()实现没有。

So with a few tweaks I created this EndTransaction() method: 因此,通过一些调整,我创建了这个EndTransaction()方法:

public void EndTransaction()
{
    try
    {
        SessionManager.Instance.CommitTransactionOn(SessionFactoryConfigPath);
    }
    finally
    {
        SessionManager.Instance.CloseSessionOn(SessionFactoryConfigPath);
    }
}

Try setting cascade="delete" to cascade="all-delete-orphan" 尝试将cascade="delete"设置为cascade="all-delete-orphan"

Also, ensure that in both instances, the parent is being read and saved by the same ISession instance. 此外,请确保在两个实例中,同一个ISession实例正在读取保存父级。 As someone commented, we need to see the implementation of your .Delete() method. 有人评论说,我们需要看到你的.Delete()方法的实现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM