我的模型包含一个类Section
,其具有的有序列表Statics
是本节的一部分。 离开所有其他属性了,该模型的实现看起来是这样的:
public class Section
{
public virtual int Id { get; private set; }
public virtual IList<Static> Statics { get; private set; }
}
public class Static
{
public virtual int Id { get; private set; }
}
在数据库中,关系实现为一个一对多,其中表Static
有一个外键指向Section
和一个整数列Position
存储在列表中它的一部分,其索引位置。
映射在功能NHibernate做过这样的:
public SectionMap()
{
Id(x => x.Id);
HasMany(x => x.Statics).Cascade.All().LazyLoad()
.AsList(x => x.WithColumn("Position"));
}
public StaticMap()
{
Id(x => x.Id);
References(x => x.Section);
}
现在我能够加载现有的Static
s,而我也能更新这些细节。 不过,我似乎无法找到一个方法来添加新的Static
s到一个Section
,而此改变保存到数据库。 我曾尝试的几种组合:
-
mySection.Statics.Add(myStatic)
-
session.Update(mySection)
-
session.Save(myStatic)
但我得到的最接近(使用前两个语句),是一个SQL异常读数:“无法将NULL值插入列‘位置’”。 显然,一个INSERT
这里尝试,但NHibernate的似乎并没有自动追加索引位置的SQL语句。
我究竟做错了什么? 我失去了我的映射的东西吗? 我需要暴露Position
列属性和值分配给它自己?
编辑:显然,一切正常,如果我删除NOT NULL
的约束Static.Position
的数据库列。 我想NHibernate的使得插入和更新立刻用行后Position
值。
虽然这是一个anwers的问题,我不知道这是否是最好的之一。 我宁愿Position
列是不可空的,所以我还是希望有一些方法,使NHibernate的提供直接在列中的值INSERT
语句。
因此,这个问题仍然是开放的。 任何其他解决办法?
当使用NHibernate的双向一个一对多关系的端部中的一个必须是“逆”。 最佳做法是设定与集合作为逆结束,因为这避免了不必要的SQL语句,并允许ID列是“不空”。
在6.4节的文档,你可以找到下面的注释:
非常重要的注意事项:如果一个协会的列声明NOT NULL,NHibernate的可能导致违反约束时,它会创建或更新关联。 为了避免这个问题,你必须使用双向关联,用标记为逆=“真”的许多有价值的一端(套或袋)。 请参阅本章后面关于双向关联的讨论。
所以,你需要.Inverse()添加到您的SectionMap映射的hasMany。
public SectionMap()
{
Id(x => x.Id);
HasMany(x => x.Statics)
.Cascade.All()
.LazyLoad()
.Inverse()
.AsList(x => x.WithColumn("Position"));
}
你也可能会想要一个添加和科,该科将删除方法/重置静态的参考以及添加/从自己收藏的去除静态到/:
public virtual void AddStatic(Static static)
{
Statics.Add(static);
static.Section = this;
}
public virtual void RemoveStatic(Static static)
{
Statics.Remove(static);
static.Section = null;
}
这些方法可以确保引用保持准确的关系的双方。
根据第6.8节的文档使用索引集合时NHibernate的不支持双向关系:
请注意,NHibernate的不支持双向one-to-many关联与索引的集合(列表,地图或数组)作为“多”端,你必须使用一组或包映射。
所以,如果你仍然有问题,可以考虑使用一个单向的关系,而不是双向的,但是这可能意味着你的外键列需要可空(根据在文章的开头的说明)。 否则,你可能需要您的收藏地图袋或集而不是一个列表。
在静态的表,你有一个名为“SectionID”或类似的东西领域。 让本场可为空:NHibernate的第一添加新的记录,然后更新所引用的ID。
我发现,在我的数据库,我也感到惊讶:为什么NH不喜欢在数据库级别适当表引用?
我想我会在我的0.02 $扔,只是因为我来到这里寻找解决你的问题,它似乎没有答案的实际工作。
你几乎没有在您的解决方案。 您的的hasMany映射是正确的。 问题是,正如你所说的,位置没有在数据库中保存更新(FWIW,当你将它设置为null,它只是“工作”,因为NULL被插入到数据库;在我看来,这不是真正的工作;) )。
我觉得有点奇怪,你需要地图上的静态类的位置也是如此,明明包括静态一个位置属性。 你不想要的位置属性是可写的,但因为它的价值是由其中的静态在列表中确定。
以下内容添加到静态
public virtual int Position
{
get
{
// Will throw exception if Section is null
// or Section.Statics is null...
return Section.Statics.IndexOf(this);
}
protected set
{
}
}
与在数据库中的地位列将被更新(记得把你的映射在你StaticMap位置)。
我猜静态的NHib代理可以更新位置字段取决于在清单中的位置(由一些魔术大于我拥有),并随后被保存到数据库。