【发布时间】:2013-12-10 18:58:58
【问题描述】:
在我的对象图中,Person 与 Address 具有多对多关系,并且连接表有额外的列。
类结构
class Person
{
private IList<PersonAddress> _personAddresses = new List<PersonAddress>();
public virtual int Id { get; set; }
public virtual IList<PersonAddress> PersonAddresses
{
get { return _personAddresses; }
set { _personAddresses = value; }
}
}
class PersonAddress
{
public virtual Person Person { get; set; }
public virtual Address Address { get; set; }
public virtual string Description { get; set; }
public override bool Equals(...) {...}
public override int GetHashCode(...) {...}
}
class Address
{
public virtual int Id { get; set; }
}
映射
class PersonMapping : ClassMapping<Person>
{
public PersonMapping()
{
Id(x => x.ID, m => m.Generator(Generators.Identity));
Bag(
x => x.PersonAddresses,
m => {
m.Cascade(Cascade.All);
m.Access(Accessor.Field);
},
r => r.OneToMany()
);
}
}
public class PersonAddressMapping : ClassMapping<PersonAddress>
{
public PersonAddressMapping()
{
ComposedId(map =>
{
map.ManyToOne(
x => x.Person,
m => {
m.Cascade(Cascade.All);
}
);
map.ManyToOne(
x => x.Address,
m => {
m.Cascade(Cascade.All);
}
);
map.Property(x => x.Description);
});
}
}
public class AddressMapping : ClassMapping<Address>
{
public AddressMapping()
{
Id(x => x.ID, m => m.Generator(Generators.Identity));
}
}
用法
using (var session = sessionFactory.OpenSession())
using (var transaction = session.BeginTransaction())
{
var person = new Person();
var address = new Address();
var personAddress = new PersonAddress
{
Address = address,
Person = person,
Description = "This is my home address"
};
person.PersonAddresses.Add(personAddress);
session.Save(person);
// exception of NHibernate.TransientObjectException
transaction.Commit();
}
例外
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: MyApp.Models.Address, Entity: MyApp.Models.Address
我相信我上面的代码应该不会有问题,因为我保存了一个Person,它级联到PersonAddress,然后级联到Address。但是,NHibernate 告诉我要么自动保存(使用级联?),要么自己保存。
解决方法
session.Save(person);
session.Save(address);
transaction.Commit();
但是,这是非常有问题的,因为实际的生产代码比简短的示例要复杂得多。在实际的生产代码中,我有一个 Organization 对象,其中包含一个 Person 列表(然后有个人地址和地址)。
有没有办法解决这个问题而无需额外调用Save,因为在尝试将我的应用程序逻辑与持久性逻辑分开时很难以通用方式编写它。
为什么该解决方法不适用于我的场景
// where unitOfWork is a wrapper for the session
using (var unitOfWork = unitOfWorkFactory.Create())
{
var organization = unitOfWork.OrganizationRepository.GetById(24151);
organization.AddPerson(new Person {
PersonAddress = new PersonAddress {
Address = new Address(),
Description = "Some description"
}
});
unitOfWork.Commit();
}
如您所见,UnitOfWork、UnitOfWorkFactory 和 OrganizationRepository 都是抽象的,因此我不可能在不泄露实现细节的情况下同时保存地址和人员,我认为我应该这样做如果持久性如我预期的那样级联,则能够做到。
我的问题是,我如何在不明确告诉 NHibernate 这样做的情况下坚持 Address?
【问题讨论】:
标签: c# .net nhibernate orm nhibernate-mapping