Fluent-NHibernate 多对多级联不会填充链接表
好的,无论我如何定义这些映射,我的多对多映射都不想与级联插入一起使用。我尝试了 Cascade() 与 Reverse() 的各种组合,并删除所有不必要的属性,只是为了了解它们是否与此不起作用但没有锁定有关。
这真的很简单:我有一个 Message
(如电子邮件),它从用户(我将实体称为 BasicUser
)发送到多个用户(通过属性至
)。对于收件人而言,User
和 Message
是多对多关系,而 FromUser
是一对多关系。 FromUser 工作正常并且更新正常,但我的问题是多对多。我什至删除了 FromUser
和关系只是为了检查这是否是问题所在,但没有帮助。
所以这是表格设计(为了简单起见,删除了从 FromUser
到 BasicUser
的关系)
以下是映射:
public class MessageMap : ClassMap<Message>
{
public MessageMap()
{
Id(x => x.Id).Column("MessageId");
Map(x => x.Subject);
Map(x => x.SentAt);
Map(x => x.Body);
References(x => x.From).Column("FromUser");
HasManyToMany(x => x.To).Table("BasicUserMessage").ChildKeyColumn("BasicUserId")
.ParentKeyColumn("MessageId").Cascade().All();
}
}
public class BasicUserMap : ClassMap<BasicUser>
{
public BasicUserMap()
{
Id(x => x.Id).Column("BasicUserId");
Map(x => x.DisplayName);
Map(x => x.Username);
HasManyToMany(x => x.Messages).Table("BasicUserMessage").ChildKeyColumn("MessageId")
.ParentKeyColumn("BasicUserId").Inverse();
}
}
我称之为此方法,但它不起作用(表 BasicUserMessage
未填充):
(注意 ID 为 1、2 和 3 的用户确实存在 - 我也尝试从数据库获取它们,然后添加到列表仍然不起作用)
ISessionFactory factory = GetSessionFactory();
ISession session = factory.OpenSession();
Message m = new Message()
{
Body = "Please note 2",
Subject = "Secret 2",
From = new BasicUser(){Id = 2},
SentAt = DateTime.Now,
};
m.To.Add(new BasicUser(){Id = 1});
m.To.Add(new BasicUser(){Id=3});
session.SaveOrUpdate(m);
session.Close();
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
关于交易的答案是偶然发生的正确性。另外,偶然发生的正确情况是,这本身就是如此表现的,因为您正在使用类似于 IDENTITY 生成器的东西,该生成器需要在保存时进行数据库访问才能获取身份。
以下是当您在多对多关联上设置
save-update
级联(或任何暗示这一点的级联)时,NHibernate 会执行的操作:保存父实体。由于身份策略,这会立即进入数据库。该集合已“修改”(因为它是新的),所以让我们看看它的成员。仅当未在父关系的映射上设置
inverse
时,才会发生此步骤。在链接表中为它们每个创建一个条目。但是等等,其中一些条目是暂时的。级联设置正确,所以没关系 - 但为了在会话中创建链接表条目,我们需要这些子项的 ID,所以让我们立即保存它们。
现在,所有相关实体都是持久的,并且会话对于链接表中的所有条目都有一个待插入。刷新会话将发出命令并创建这些条目。
当您将代码包装在事务中时,提交事务会刷新会话,以便在提交时创建会话。如果您使用不需要数据库往返的身份生成器,则链接表条目和实体都会同时插入,因此您不会看到所看到的“断开连接” - 如果会话永远不会被刷新,也不会插入任何内容,并且当刷新时,所有内容都会被插入。如果您没有这些东西,显式刷新会话将创建链接表条目,一切都会好起来的。
The answer about transactions is correct-by-incidental-occurrence. Also correct-by-incidental occurrence is that this is manifesting itself as such because you are using something like an
IDENTITY
generator that requires a database trip on save to obtain the identity.Here is what NHibernate does when you set a
save-update
cascade (or any cascade which implies that) on a many-to-many association with such:Save the parent entity. This goes to the database immediately because of the identity strategy. The collection is "modified" (because it's new), so let's look at it's members. This step only occurs if
inverse
is not set on the parent's mapping of the relationship. Create an entry in the link table for each of them.But wait, some of these entries are transient. Cascades are set properly, so that's okay - but in order to create the link table entry in the session, we need the id of those children, so let's save them immediately.
Now all relevant entities are persistent, and the session has a pending insert for all of the entries in the link table. Flushing the session will issue the commands and create those entries.
When you wrap your code in a transaction, committing the transaction flushes the session, so that is created when you commit. If you use an identity generator that doesn't require a DB round-trip, then the link table entries and the entities are all inserted at the same time, so you won't see the "disconnect" that you're seeing - if the session is never flushed, nothing is ever inserted, and when it is flushed, everything is inserted. If you have neither of these things, flushing your session explicitly will create the link table entries and all will be well.
您将两个引用都颠倒了。这对NH意味着:不要从这一侧存储它,因为它已经被另一侧存储了。如果两者都相反,则不存储任何内容。
从参考文献之一中删除 Inverse。
You made both references inverse. This means to NH: don't store it from this side, because it is already stored by the other side. If both are inverse, nothing is stored.
Remove Inverse from one of the references.
您需要将代码包装在事务中。否则 Nhibernate 不会在连接表中保存值
You need to wrap your code in transaction. Otherwise Nhibernate won't save values in joining table
您需要使 BasicUser 对象持久化:
这当然应该在事务中完成(正如 Sly 回答的那样),并且会话应该包装在 using 语句中。
You need to make the BasicUser objects persistent:
This should of course be done in a transaction (as Sly answered) and the session should be wrapped in a using statement.