Cascade不能像我期望的那样工作

时间:2011-05-17 16:17:23

标签: nhibernate fluent-nhibernate cascade fluent cascading-deletes

我对配置NHibernate相对较新,并遇到了问题。我有以下实体:

public class Report
{
    public virtual int Id { get; private set; }
    public virtual string Name { get; private set; }
    public virtual string Path { get; private set; }
    public virtual string Alias { get; private set;}

    public virtual IList<Tab> Tabs
    {
        get; private set;
    }
}

public class Tab
{
    public virtual string Name { get; private set; }
    public virtual string Description { get; private set; }
    public virtual IList<Section> Sections { get; set; }
    public virtual Report ParentReport { get; private set; }
}

public class Section
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
}

我使用Fluent NHibernate和Auto Mapping来映射关系。

.Database(MsSqlConfiguration.MsSql2005.ShowSql().ConnectionString(c => c.Is(connectionString)))                
.Mappings(map => map.AutoMappings.Add(AutoMap.AssemblyOf<Workbook>(configuration)
.Conventions.AddFromAssemblyOf<CascadeAll>()

问题在于,无论我在CascadeAll类中选择哪种级联选项,我都无法按照我的意愿执行它。

当我从给定报表中删除Tab时,我希望从数据库中删除选项卡上的部分,然后从数据库中的报表中删除选项卡。

Cascade.All()

删除Report和Tab之间的关系,但将选项卡设置ParentReport_id孤立为null。

Cascade.AllDeleteOrphan() 

这将删除与报告关联的所有部分,选项卡,然后删除报告,尽管只从报告中的集合中删除一个选项卡。

Cascade.SaveUpdate() 

像All一样的行为,或者选择标签。

顺便提一下,这些都是通过从Report上的选项卡集合中删除选项卡然后调用session.SaveUpdate(instance)&gt;来调用的。其中实例是正在更新的报表实例。

我知道如何解决这个或我做错了什么?

2 个答案:

答案 0 :(得分:1)

感谢雷克斯,我怀疑你的建议会有用,所以我可以尝试一下。这完全取决于Report和Tab之间的关系,导致OneToMany(Report-&gt; Tab)和ManyToOne(Tab-&gt; Report)。使用我选择的级联选项,它可以是NUll外键,也可以删除选项卡,所有其他选项卡和报告。这与AllDeleteOrphan有关。

当我删除标签时 - &gt;报告ManyToOne关系孤立记录被删除没有删除Repotr。最后,我快速选择创建一个显式映射文件,该文件在ReportMapping文件中使用HasMany(x =&gt; x.Tabs).... TabMapping上的引用(x =&gt; x.ParentReport)...

感谢您的帮助。

答案 1 :(得分:0)

听起来你需要结合使用这些。当您需要除惯例提供的默认值以外的其他内容时,您可以为特殊情况编写overrides

如果你的覆盖中出现的模式在大多数情况下都是正确的,你可以创建一个新的约定来处理它,而不是每次都要指定覆盖。

我相信您希望.AllDeleteOrphan()用于Sections收藏,并使用.All()收集Tabs收藏。

在您的情况下,我相信您的覆盖会看起来像这样。

public class ReportMappingOverride : IAutoMappingOverride<Report>
{
    public void Override(AutoMapping<Report> mapping)
    {
        // You don't need this, but I'll leave it for an example...
        //mapping.HasMany(x => x.Tabs).Cascade.All();
    }
}

public class TabMappingOverride : IAutoMappingOverride<Tab>
{
    public void Override(AutoMapping<Tab> mapping)
    {
        // You don't need this, but I'll leave it for an example...
        //mapping.HasMany(x => x.Sections).Cascade.AllDeleteOrphan();
        // This should prevent deletes from being cascaded to the Report
        //   (which would delete the report).
        mapping.References(x => x.ParentReport).Cascade.SaveUpdate();
    }
}

要使用覆盖,您的配置会稍微改变一下,看起来像这样。

.Mappings(map => map.AutoMappings.Add(AutoMap.AssemblyOf<Workbook>(configuration).UseOverridesFromAssemblyOf<ReportMappingOverride>()

将属性返回到父报告无关紧要,但是为了进行测试,您可以将其取出并查看是否存在问题。