我在NHibernate中收到“保存未保存的瞬态实体”错误。我有一个聚合根neighborhood
,其中包含addresses
和person
,这里有一些快速伪代码来解释这种关系:
public class Neighborhood {
public virtual int Id { get; set; }
public virtual IList<Address> Addresses { get; set; }
}
public class Address {
public virtual int Id { get; set; }
public virtual string Address { get; set; }
public virtual Person Person { get; set; } //Assume only one person per address
}
public class Person {
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
在我的邻居地图中,我有:
mapping.HasMany(x => x.Addresses)
.Inverse()
.KeyColumn("NeighborhoodFk")
.Cascade.All()
.AsBag();
在我的代码中,我经常想要创建一个并同时关联一个地址和人员:
var address = new Address();
var person = new Person();
var address.Person = person;
var neighborhood = neighborhoodRepository.Get(id);
neighborhood.Add(address);
neighborhoodRepository.DbContext.BeginTransaction();
neighborhoodRepository.SaveOrUpdate(neighborhood);
neighborhoodRepository.DbContext.CommitTransation();
我会在Person
实体上收到“未保存的瞬态实体”错误,因为它附加到瞬态实体Address
。
我可以看到的唯一方法是首先保存address
,在更新后再次调用数据库以更新neighborhood
,搜索我刚刚添加的address
,附上person
,然后再次保存。
有什么我想念的东西让这更容易吗?这似乎是一个常见的用例,我不想在数据库中进行一堆往返。
答案 0 :(得分:5)
确保将地图到人的映射的“级联”属性设置为“保存更新”或“全部”。你有从邻居到地址的级联,但你没有声明这个较低的级联存在。如果不是,那么您收到此错误不是因为Person附加到临时地址,而是因为地址引用了临时Person。
如果由于某种原因无法生成此级联,请首先保存Person,然后保存邻居,它将级联到地址,ORM将在其会话中找到引用的Person并设置引用。这可能会导致一些额外的“往返”,具体取决于您是否让NH或DB生成自动编号列。 NHibernate很棘手,因为它会在好的和准备好的情况下进行DB调用,这可能是在整个对象图在NH会话之后,或者仅仅是人。无论哪种方式,它都会对每个持久化对象的数据库进行插入调用,因此无论将项目添加到会话中的代码如何,它都会进行多次“往返”。