Nhibernate 集合。子实体未保存
Nhibernate collections .Child entities not saved
使用
.NET Core SDK (reflecting any global.json):
Version: 2.2.300
Commit: 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 );
}
我得到以下异常
Unhandled Exception: NHibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing or set cascade action for the property to something that would make it autosave. Type: Nhibernate.ConsoleApp.Entities.Site, Entity: [Site 0]
有什么建议吗?
编辑
实际上问题出在不同的区域。这是因为存在两个已注册的侦听器(IDeleteEventListener
和 IUpdateEventListener
)。每当我添加那些更新和删除时都不起作用。但是,由于 Roman Artiukhin 评论
,我能够发现问题
例外是 telling 根实体 Customer
持有对其他 (Site
) 实体的引用,该实体是临时实体。这就是为什么不能持久化根实体的原因。
Scenario 1: No cascade options were configured.
In this case the child or referenced objects must be saved first.
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
}
这应该有效。
Scenario 2: Cascade options were not configured for all INPUT; UPDATE or DELETE operations.
In this case the configuration must be changed or child or referenced objects must be saved first.
您已经:
- 设置
collection.Inverse( true );
- 通过扩展方法
Include
添加了两个 DeleteOrphans | Persist
values for Cascade
。
所以这不是问题。
Scenario3: Related transient objects where instantiated and associated to the persitent object but no save operation is to be performed on those objects.
In this case the trainsient objects must be detached from the current session through the command:
ISession.Evict(obj)
而不是 Evict
,您可以调用 Save
来显式附加那些对象,如上所述。
要获得更多见解,请查看 documentation,其中解释了各种策略。
我猜 collection 不是你的问题。看起来你在其他地方暴露了 Site
实体(例如 many-to-one customer.LastSite
属性 或类似的东西)。级联逻辑在 collection 保存之前偶然发现了这个尚未保存的 Site
属性。所以你必须确保其他 Site
属性也有 Cascade.Persist
映射
使用
.NET Core SDK (reflecting any global.json): Version: 2.2.300 Commit: 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 );
}
我得到以下异常
Unhandled Exception: NHibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing or set cascade action for the property to something that would make it autosave. Type: Nhibernate.ConsoleApp.Entities.Site, Entity: [Site 0]
有什么建议吗?
编辑
实际上问题出在不同的区域。这是因为存在两个已注册的侦听器(IDeleteEventListener
和 IUpdateEventListener
)。每当我添加那些更新和删除时都不起作用。但是,由于 Roman Artiukhin 评论
例外是 telling 根实体 Customer
持有对其他 (Site
) 实体的引用,该实体是临时实体。这就是为什么不能持久化根实体的原因。
Scenario 1: No cascade options were configured.
In this case the child or referenced objects must be saved first.
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
}
这应该有效。
Scenario 2: Cascade options were not configured for all INPUT; UPDATE or DELETE operations.
In this case the configuration must be changed or child or referenced objects must be saved first.
您已经:
- 设置
collection.Inverse( true );
- 通过扩展方法
Include
添加了两个DeleteOrphans | Persist
values forCascade
。
所以这不是问题。
Scenario3: Related transient objects where instantiated and associated to the persitent object but no save operation is to be performed on those objects.
In this case the trainsient objects must be detached from the current session through the command:ISession.Evict(obj)
而不是 Evict
,您可以调用 Save
来显式附加那些对象,如上所述。
要获得更多见解,请查看 documentation,其中解释了各种策略。
我猜 collection 不是你的问题。看起来你在其他地方暴露了 Site
实体(例如 many-to-one customer.LastSite
属性 或类似的东西)。级联逻辑在 collection 保存之前偶然发现了这个尚未保存的 Site
属性。所以你必须确保其他 Site
属性也有 Cascade.Persist
映射