好的,无论我如何定义这些映射,我的多对多映射都不希望使用级联插入。我尝试了Cascade()
和Reverse()
的各种组合,并删除了所有不必要的属性,只是为了了解它们是否与此无关,但没有锁定。
这是非常简单的东西:我有一个Message
(就像一封电子邮件),它是从用户(我称之为实体BasicUser
)发送给多个用户(通过属性{{ 1}})。关于收件人,To
和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();
}
}
没有填充):
(注意Id 1,2和3的用户确实存在 - 我也尝试从数据库中获取它们然后添加到列表仍然无效)
BasicUserMessage
答案 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语句中。