好的,这将是一个文本墙,但......基本上,我有以下3个类:
public class Address
{
public virtual int Id { get; private set; }
public virtual string Street { get; set; }
public virtual string POBox { get; set; }
public virtual string ZIP { get; set; }
public virtual string Locality { get; set; }
public virtual Country Country { get; set; }
public virtual ICollection<Customer> CustomersLivingHere { get; set; }
}
public class Customer
{
public virtual int Id { get; private set; }
public virtual string Firstname { get; set; }
public virtual string Lastname { get; set; }
public virtual DateTime Birthdate { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
}
public class Country
{
public virtual int Id { get; private set; }
public virtual string Name { get; set; }
public virtual string Domain { get; set; }
}
这是某种地址簿(在现实世界中显然有点复杂,但我已将单元测试减少到这个非工作情况)。
地址使用第三方提供的Web服务进行验证和规范化,理想情况下,我希望客户和地址之间的关系是多对多的,因此数据库中的每个地址都需要只能验证一次(我们为验证服务付钱),同时仍然与任意数量的客户相关联。
与此同时,我希望NHibernate在将地址分配给客户对象后自动存储地址并保存,但到目前为止,这根本不起作用。
这是我的映射文件查找Customer类的方式:
public class CustomerMap : FluentNHibernate.Mapping.ClassMap<Customer>
{
public CustomerMap()
{
Id(x => x.Id);
Map(x => x.Firstname).Length(256);
Map(x => x.Lastname).Length(256);
Map(x => x.Birthdate);
HasMany(x => x.Addresses)
.AsSet()
.Inverse()
.Cascade.All();
}
}
...这是地址映射:
public class AddressMap : FluentNHibernate.Mapping.ClassMap<Address>
{
public AddressMap()
{
Id(x => x.Id);
Map(x => x.Street);
Map(x => x.POBox);
Map(x => x.ZIP).Length(16).Not.Nullable();
Map(x => x.Locality).Length(128).Not.Nullable();
References(x => x.Country).Not.Nullable();
HasManyToMany(x => x.CustomersLivingHere)
.Table("CustomerAddress");
}
}
我期望做的事情基本上就是:
国家someCountry =新国家/地区 { 代码=“CL”, DialPrefix =“+ 56”, 名称=“智利”, Domain =“。ccl” };
Address[] Addresses = new[] {
new Address
{
Country = someCountry,
Locality = "Providencia",
Street = "Pasaje Anakena 123",
ZIP = "7510115"
},
new Address
{
Country = someCountry,
Locality = "Providencia",
Street = "Perez Valenzuela 1520",
ZIP = "7500035"
}
};
Customer[] Customers = new[] {
new Customer
{
Addresses = new[] {Addresses[0], Addresses[1]},
Firstname = "Jane",
Lastname = "Doe"
}
};
using (ISession session = _sessionFactory.OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
foreach (Customer customer in Customers)
{
session.Save(customer);
}
transaction.Commit();
}
}
运行包含与此类似的代码的单元测试基本上会产生 NHibernate.StaleStateException:意外的行数:0;预期:1 我阅读了大约35个博客条目和SO问题,但那些主要处理指定的ID,我没有使用 - 我看了一下Fluent Hibernate生成的映射文件,而生成器类总是“身份”。
我看了一下NHibernate的SQL输出和调试日志,似乎NHibernate以某种方式将id分配给某些对象而不是默认值导致NHibernate尝试发出UPDATE而不是SELECT语句 - 我不知道但是,为什么呢。
任何有关如何纠正这一点的见解,甚至是以良好方式建模这种关系的一般提示肯定会受到赞赏。
答案 0 :(得分:2)
您已将Customer-&gt;地址映射为一对多关系(您的流利映射中的客户HasMany地址),但地址 - &gt;客户为多对多关系。 NHibernate将表示Customer-&gt; Address(HasMany)作为Address表上的CustomerId外键。这不是你想要的。
public class CustomerMap : FluentNHibernate.Mapping.ClassMap<Customer>
{
public CustomerMap()
{
Id(x => x.Id);
Map(x => x.Firstname).Length(256);
Map(x => x.Lastname).Length(256);
Map(x => x.Birthdate);
HasManyToMany(x => x.Addresses)
.Table("CustomerAddress")
.Inverse()
.Cascade.All();
}
}
这种类型的双向多对多映射在NHibernate文档中进行了讨论:
http://nhibernate.info/doc/nh/en/index.html#collections-bidirectional