Fluent-NHibernate多对多级联不会填充链接表

时间:2011-03-17 13:54:26

标签: c# .net nhibernate fluent-nhibernate many-to-many

好的,无论我如何定义这些映射,我的多对多映射都不希望使用级联插入。我尝试了Cascade()Reverse()的各种组合,并删除了所有不必要的属性,只是为了了解它们是否与此无关,但没有锁定。

这是非常简单的东西:我有一个Message(就像一封电子邮件),它是从用户(我称之为实体BasicUser)发送给多个用户(通过属性{{ 1}})。关于收件人,ToUser具有多对多关系,但Message具有一对多关系。 FromUser工作正常,它更新正常,但我的问题是多对多。我甚至删除了FromUser和关系只是为了检查这是否是问题,但没有帮助。

所以这是表格设计(为简单起见,已删除了从FromUserFromUser的关系)

enter image description here

以下是映射:

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(); } } 没有填充): (注意Id 1,2和3的用户确实存在 - 我也尝试从数据库中获取它们然后添加到列表仍然无效)

BasicUserMessage

4 个答案:

答案 0 :(得分:6)

关于交易的答案是偶然发生的。同样正确的发生是因为你正在使用类似IDENTITY生成器之类的东西,需要在保存时获取数据库,以获取身份。

以下是NHibernate在与多对多关联设置save-update级联(或暗示的任何级联)时所做的事情:

保存父实体。由于身份策略,这会立即进入数据库。该集合被“修改”(因为它是新的),所以让我们来看看它的成员。如果未在父级关系映射上设置inverse,则只会执行此步骤。在链接表中为每个条目创建一个条目。

但等等,其中一些条目是暂时的。 Cascades设置正确,所以没关系 - 但是为了在会话中创建链接表条目,我们需要这些子节点的id,所以让我们立即保存它们。

现在所有相关实体都是持久性的,并且会话对链接表中的所有条目都有挂起插入。刷新会话将发出命令并创建这些条目。

当您将代码包装在事务中时,提交事务会刷新会话,以便在您提交时创建。如果您使用不需要DB往返的身份生成器,那么链接表条目和实体都会同时插入,因此您将看不到您所看到的“断开连接” - 如果会话永远不会被刷新,什么都没有被插入,当它被刷新时,一切都被插入。如果你没有这些东西,那么显式刷新你的会话将创建链接表条目,一切都会很好。

答案 1 :(得分:5)

你们两个引用都是反向的。这意味着NH:不要从这一侧存储它,因为它已经存储在另一侧。如果两者都是反向的,则不存储任何内容。

从其中一个参考文献中删除反向。

答案 2 :(得分:4)

您需要将代码包装在事务中。否则Nhibernate将不会在连接表中保存值

答案 3 :(得分:0)

您需要使BasicUser对象持久化:

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,
                };
var basicUser1 = new BasicUser(){Id = 1};
session.Save(basicUser1);
m.To.Add(basicUser1);
var basicUser3 = new BasicUser(){Id = 3};
session.Save(basicUser3);
m.To.Add(basicUser3);
session.Save(m);
session.Flush();

这当然应该在一个事务中完成(如Sly回答),并且会话应该包含在using语句中。