如何使用 NHibernate 将新对象添加到映射为一对多的 IList?
我的模型包含一个 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
有一个外键指向 < code>Section 和一个整数列 Position
来存储其索引位置在它所属的列表中。
映射是在 Fluent 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
添加到 Section
中,并将此更改保留到数据库中。 我尝试了以下几种组合:
mySection.Statics.Add(myStatic)
session.Update(mySection)
session.Save(myStatic)
但我得到的最接近的结果(使用前两条语句)是 SQL 异常读取:“无法将 NULL 值插入列‘位置’”。 显然,这里尝试了 INSERT,但是 NHibernate 似乎没有自动将索引位置附加到 SQL 语句中。
我究竟做错了什么? 我的映射中是否遗漏了某些内容? 我是否需要将 Position
列公开为属性并自己为其分配值?
编辑:显然,如果我删除数据库中 Static.Position
列上的 NOT NULL
约束,一切都会按预期工作。 我猜想 NHibernate 会在使用 Position
值更新行后立即进行插入。
虽然这是问题的答案,但我不确定这是否是最好的答案。 我希望 Position
列不可为空,因此我仍然希望有某种方法可以让 NHibernate 直接在 INSERT
语句中为该列提供值。
因此,这个问题仍然悬而未决。 还有其他解决方案吗?
My model contains a class Section
which has an ordered list of Statics
that are part of this section. Leaving all the other properties out, the implementation of the model looks like this:
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; }
}
In the database, the relationship is implemented as a one-to-many, where the table Static
has a foreign key pointing to Section
and an integer column Position
to store its index position in the list it is part of.
The mapping is done in Fluent NHibernate like this:
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);
}
Now I am able to load existing Static
s, and I am also able to update the details of those. However, I cannot seem to find a way to add new Static
s to a Section
, and have this change persisted to the database. I have tried several combinations of:
mySection.Statics.Add(myStatic)
session.Update(mySection)
session.Save(myStatic)
but the closest I have gotten (using the first two statements), is to an SQL exception reading: "Cannot insert the value NULL into column 'Position'". Clearly an INSERT
is attempted here, but NHibernate does not seem to automatically append the index position to the SQL statement.
What am I doing wrong? Am I missing something in my mappings? Do I need to expose the Position
column as a property and assign a value to it myself?
EDIT: Apparently everything works as expected, if I remove the NOT NULL
constraint on the Static.Position
column in the database. I guess NHibernate makes the insert and immediatly after updates the row with a Position
value.
While this is an anwers to the question, I am not sure if it is the best one. I would prefer the Position
column to be not nullable, so I still hope there is some way to make NHibernate provide a value for that column directly in the INSERT
statement.
Thus, the question is still open. Any other solutions?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
当在 NHibernate 中使用双向一对多关系时,其中一端必须是“反向”。 最佳实践是将集合的结尾设置为相反,因为这样可以避免不必要的 SQL 语句并允许 id 列“不为空”。
在文档的 第 6.4 节中,您可以找到以下注释:
因此,您需要将 .Inverse() 添加到 SectionMap 中的 HasMany 映射中。
您可能还需要在部分上添加和删除方法,该方法设置/重置静态的引用以及向/从其自己的集合中添加/删除静态:
这些方法确保引用在两侧都保持准确。的关系。
根据文档的 第 6.8 节,NHibernate 不使用索引集合时支持双向关系:
因此,如果您仍然遇到问题,请考虑使用单向关系而不是双向关系,但这可能意味着您的外键列需要可为空(根据帖子开头的注释)。 否则,您可能必须将您的收藏映射为包或集合而不是列表。
When using a bidirectional one-to-many relationship in NHibernate one of the ends must be "inverse". Best practice is to set the end with the collection as inverse, since that avoids unnecessary SQL statements and allows the id column to be "not null".
In section 6.4 of the documentation you can find the following note:
So, you need to add .Inverse() to your HasMany mapping in SectionMap.
You would also probably want an Add and Remove method on Section, which sets/resets the reference of the static as well as adding/removing the static to/from its own collection:
These methods makes sure the references are kept accurate on both sides of the relationship.
According to section 6.8 of the docs NHibernate does not support bidirectional relationships when using indexed collections:
So, if you are still having trouble, consider using a unidirectional relationship instead of a bidirectional, however that might mean that your foreign key column needs to be nullable (according to the note in the beginning of the post). Otherwise you might have to map your collection as a bag or set instead of a list.
我想我应该投入 0.02 美元,只是因为我来这里是为了解决你的问题,但似乎没有一个答案真正有效。
您的解决方案即将完成。 您的 HasMany 映射是正确的。 问题是,正如您所说,位置不会在数据库中更新(FWIW,当您将其设置为 null 时,它只能“起作用”,因为 NULL 被插入到数据库中;对我来说,这实际上不起作用;) )。
我觉得有点奇怪,您也需要在 Static 类上映射位置,并且显然在 Static 上包含一个 Position 属性。 不过,您不希望 Position 属性可写,因为它的值由 Static 在列表中的位置决定。
将以下内容添加到 Static 中,
数据库中的 Position 列中的内容将被更新(请记住在 StaticMap 中映射您的 Position)。
我猜测 Static 的 NHib 代理可以根据它在列表中的位置来更新 Position 字段(通过一些比我拥有的魔法更大的魔法),然后将其保存到数据库中。
I thought I'd throw in my $0.02, only because I came here looking to solve your problem and it seems none of the answers actually work.
You are nearly there in your solution. Your mapping for the HasMany is correct. The problem is, as you've said, the Position doesn't get updated in the database (FWIW when you set it to null, it only "works" because NULL gets inserted into the DB; to me that's not really working ;)).
I find it a bit strange, you need to Map the position on your Static class too, and obviously include a Position property on Static. You don't want the Position property to be writable though, because it's value is determined by where Static is in the list.
Add the following to Static
With that in the Position column in the db will be updated (remember to map your Position in your StaticMap).
I'm guessing the NHib proxy of Static can update the Position field depending on it's position in the list (by some magic greater than I possess) and that then gets saved to the db.
在静态表中,有一个名为“SectionID”或类似字段的字段。
让这个字段可以为 NULL:NHibernate 首先添加新记录,然后更新引用的 id。
我在我的数据库中发现了这一点,我也很惊讶:为什么 NH 不喜欢数据库级别的正确表引用?
In the Static's table you have a field called "SectionID" or something similar.
Let this field be NULLable: NHibernate first adds the new record, then updates the referenced id.
I have found that in my db and I am surprised too: why the NH doesn't like proper table references at database level?