Nhibernate集合。未保存子实体

时间:2019-07-07 15:19:06

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

使用

  

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

  

Nhibernate 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评论

,我得以发现问题所在

2 个答案:

答案 0 :(得分:2)

例外情况是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:相关的临时对象已实例化并与持久对象相关联,但不对这些对象执行保存操作。
  在这种情况下,必须通过以下命令将训练对象与当前会话分离:   ISession.Evict(obj)

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

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

答案 1 :(得分:1)

我的猜测是收藏不是您的问题。看来您在其他地方暴露了Site实体(例如多对一customer.LastSite属性或类似内容)。并且在保存集合之前,级联逻辑偶然发现了这个尚未保存的Site属性。因此,您必须确保其他Site属性也具有Cascade.Persist映射