【问题标题】:Nhibernate collections .Child entities not savedNhibernate 集合 .Child 实体未保存
【发布时间】:2019-11-17 07:00:39
【问题描述】:

使用

.NET Core SDK(反映任何 global.json): 版本:2.2.300 提交:73efd5bd87

休眠 5.2.5

拥有以下实体

public class Customer : Entity {
    public Customer() {
        Initialize();
    }
    public virtual string Name { get; set; }
    public virtual string LegalName { get; set; }
    public virtual string VATCode { get; set; }
    public virtual ICollection<Site> Sites { get; set; }
    public virtual DateTime Created { get; set; } = DateTime.UtcNow;

    private void Initialize() {
        Sites = new List<Site>();
    }
}

public class Site : Entity {
    public virtual string Address { get; set; }
    public virtual string City { get; set; }
    public virtual string Country { get; set; }
    public virtual Customer Customer { get; set; }
}

使用以下映射器

internal class CustomerConfiguration : ClassMapping<Customer> {
    public CustomerConfiguration() {
        Table( TableNames.CustomersTable );

        Id( x => x.EntityID, im => {
            im.Column( "CustomerID" );
            im.Generator( Generators.Identity );
        } );
        [... code omitted for brevity ...]
        Set<Site>( property => property.Sites,
            collection => {
                collection.Fetch( CollectionFetchMode.Join );
                collection.Lazy( CollectionLazy.Lazy );
                collection.Cascade( Cascade.Persist.Include( Cascade.DeleteOrphans ) );
                collection.Inverse( true );
                collection.Key( keyMapping => {
                    keyMapping.Column( "CustomerID" );
                } );
            },
            mapping => {
                mapping.OneToMany( relationalMapping => {
                    relationalMapping.Class( typeof( Site ) );
                } );
            } );
    }
}

internal class SiteConfiguration : ClassMapping<Site> {
    public SiteConfiguration() {
        Table( TableNames.SitesTable );

        Id( x => x.EntityID, im => {
            im.Column( "SiteID" );
            im.Generator( Generators.Identity );
        } );
        [... code omitted for brevity ...]
        ManyToOne( x => x.Customer, mm => {
            mm.Column( "CustomerID" );
            mm.NotNullable( true );
        } );
    }
}

我猜这个映射不正确,因为如果我做类似的事情

using ( var session = sessionFactory.OpenSession() ) {
    var customer = new Customer() {
        Name = $"Customer 1",
        LegalName = $"Customer 1 LLC",
        VATCode = "xxxxxxxxx",
        Created = DateTime.UtcNow
    };
    customer.Sites.Add( new Site() {
        Address = $"Address Customer 1",
        City = $"City Customer 1",
        Country = $"Country Customer 1",
        Customer = customer
    } );
    session.Save( customer );
}

我得到以下异常

未处理的异常:NHibernate.TransientObjectException:对象引用了未保存的瞬态实例 - 在刷新之前保存瞬态实例或将属性的级联操作设置为使其自动保存的内容。类型:Nhibernate.ConsoleApp.Entities.Site,实体:[Site 0]

有什么建议吗?

编辑

实际上问题出在不同的区域。这是因为存在两个已注册的侦听器(IDeleteEventListenerIUpdateEventListener)。每当我添加这些更新和删除都不起作用。但是,感谢Roman Artiukhin 评论,我能够发现问题

【问题讨论】:

  • @Alexander 我确实阅读了所有引用的帖子,但除非我没有得到区别,否则就我而言,没有复合 ID。两个表都使用代理键作为数据库标识列。我已更新问题以添加映射 ID。能详细点吗?

标签: asp.net-core nhibernate nhibernate-mapping asp.net-core-2.2


【解决方案1】:

例外是 telling 根实体 Customer 持有对其他 (Site) 实体的引用,该实体是临时实体。这就是为什么根实体不能被持久化的原因。

场景 1:未配置级联选项。
在这种情况下,必须先保存子对象或引用对象。

using ( var session = sessionFactory.OpenSession() ) {
    var customer = new Customer() {
        Name = $"Customer 1",
        LegalName = $"Customer 1 LLC",
        VATCode = "xxxxxxxxx",
        Created = DateTime.UtcNow
    };
    Site site = new Site() {
        Address = $"Address Customer 1",
        City = $"City Customer 1",
        Country = $"Country Customer 1",
        Customer = customer
    }
    customer.Sites.Add(site);
    session.Save( customer );//<--Save the master
    session.Save( site );//<--Save the site
    ...
    ...
    ...
    session.Flush();//<--You are calling this somewhere in your code
}

这应该可行。

场景 2:没有为所有 INPUT 配置级联选项; UPDATE 或 DELETE 操作。
在这种情况下,必须先更改配置或者必须先保存子对象或引用对象。

你已经:

所以这不是问题。

场景 3:相关瞬态对象已实例化并与持久对象相关联,但不对这些对象执行保存操作。
在这种情况下,trainsient 对象必须通过以下命令从当前会话中分离出来: ISession.Evict(obj)

您可以调用Save 来代替Evict 来显式附加这些对象,如上所述。

要了解更多信息,请查看documentation,其中解释了各种策略。

【讨论】:

  • 您的建议完全正确。该问题与侦听器注册有关。请看看我的编辑。
【解决方案2】:

我猜收藏不是你的问题。似乎您在其他地方暴露了 Site 实体(例如多对一 customer.LastSite 属性或类似的东西)。级联逻辑在保存集合之前偶然发现了这个尚未保存的Site 属性。所以你必须确保其他Site属性也有Cascade.Persist映射

【讨论】:

  • 实际上这不是正确的答案,但由于这个原因,我能够找到恰好在侦听器注册中的错误。每当我为PostInsert 事件添加侦听器时,当我执行Session.Create 时,就会调用该侦听器。但是,如果我为PostUpdatePostDelete 添加一个侦听器,就会发生一些奇怪的事情:(1)当我执行Session.UpdateSession.Delete 和(2)UpdateDelete 方法时,永远不会调用侦听器987654334@ 停止工作。请看看我的编辑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多