Fluent-NHibernate many-to-many cascade does not populate the link table

混江龙づ霸主 提交于 2019-12-05 02:09:29

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.

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.

You need to wrap your code in transaction. Otherwise Nhibernate won't save values in joining table

You need to make the BasicUser objects persistent:

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();

This should of course be done in a transaction (as Sly answered) and the session should be wrapped in a using statement.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!