我有两个实体,Shelf
和Product
:
public class Shelf
{
public virtual IList<Product> Products { get; set; }
public Shelf()
{
Products = new List<Product>();
}
}
public class Product
{
public virtual string Name { get; set; }
}
基本上,Shelf
可以包含多个Products
,而Product
可以放在许多Shelves
上。因此,Shelf
和Product
之间存在单向的多对多关系。当我运行以下代码时:
var shelf = new Shelf();
var product = new Product { Name = "Peas" };
shelf.Products.Add(product);
using (var session = SessionFactory.OpenSession())
{
session.Save(shelf);
}
NHibernate将保存Product
和Shelf
,但不保存它们之间的关系,因此如果您检索Shelf
,它将包含零Products
}。
但是,如果我添加session.Flush()
来电,则会正确保存关系,以便检索Shelf
将返回一个Product
。
此博文详细介绍了我的问题:
http://www.neeraj.name/2005/07/02/hibernate-session-close-does-not-call-session-flush.html
但是,我想知道为什么我需要session.Flush()
这个电话。保持具有正确级联行为的Shelf
将保存Product
似乎是违反直觉的,但是除非我刷新会话,否则无法建立两者之间的关系。在我看来,Save()
调用应该保存所有内容,而不仅仅是没有关系的实体本身。
答案 0 :(得分:1)
Save
仅标记要保留的实体并生成标识符。它不会持续更改数据库。
所有更改(插入,更新和删除)都在flushing执行,这可能会在不同时刻发生。
但是,也应始终使用交易。正确的工作流程是(大致):
using (var session = factory.OpenSession())
using (var tx = session.BeginTransaction())
{
//create and manipulate objects
session.Save(newObjectToBePersisted);
tx.Commit();
}
答案 1 :(得分:0)
我不确定,但也许是因为主键。当您保存两个trancident对象并使用Identity
作为主键生成模型时,Nhibernate不知道多对多连接表的Id。
在真实的单词用法中,你应该总是用Transactions中的实体包装所有操作。提交事务时,所有更改都将刷新到数据库。在您提交之前,为什么要尝试选择已经选择的实体?
答案 2 :(得分:0)
您使用手动冲洗模式吗?如果你将它设置为auto,它会在需要时立即执行。如果您在交易中运行,则需要执行session.getTransaction().commit()
以确保更改有效。 Hibernate将在运行可能具有错误结果的查询之前或在提交事务之前刷新会话。
您可以配置hibernate以在保存父对象时保存子对象的集合。阅读有关传递持久性的部分(在下面链接的文档页面,注释中)
(免责声明:我使用java hibernate,而不是NHibernate)