2010-09-15 66 views
1

我有两个实体,一个ShelfProduct为什么Session.Flush()需要保持关系?

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放。因此,ShelfProduct之间存在单向多对多关系。当我运行下面的代码:

var shelf = new Shelf(); 
var product = new Product { Name = "Peas" }; 
shelf.Products.Add(product); 

using (var session = SessionFactory.OpenSession()) 
{ 
    session.Save(shelf); 
} 

的NHibernate将保存ProductShelf,但它不会救他们之间的关系,因此,如果您检索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()调用应该节省所有内容,而不仅仅是实体本身没有他们的关系。

回答

1

Save不仅标志着被持久化的实体,并生成一个标识符。它不会保留对数据库的更改。

flushing发生在不同时刻,所有更改(插入,更新和删除)。

但是,交易也应该始终使用。正确的工作流是(大约):

using (var session = factory.OpenSession()) 
using (var tx = session.BeginTransaction()) 
{ 
    //create and manipulate objects 
    session.Save(newObjectToBePersisted); 
    tx.Commit(); 
} 
+0

感谢迭戈,这完美地回答了我的问题! – 2010-09-15 19:16:27

0

我不知道肯定,但也许是因为主键的。当您保存两个trancident对象并使用Identity作为主键生成模型时,Nhibernate不知道多对多连接表的Id。

在现实词的用法你应该总是包装所有操作在交易的实体。当您提交事务时,所有更改都将刷新到数据库。在你提交之前,你为什么要尝试选择已经选择的实体?

0

是否使用手动冲洗模式?如果您将其设置为自动,则会在需要时立即执行。如果您在交易中运行,则需要执行session.getTransaction().commit()以确保更改不变。 Hibernate会在运行一个可能有错误结果的查询之前或在提交事务之前刷新会话。

你可以配置Hibernate救子对象的集合,当父被保存。阅读关于持久性传递的部分

(以下链接,在注释文档页)(声明:我用java休眠,不NHibernate的)

+0

文档说明休眠模式冲洗是在这里:http://docs.jboss.org/hibernate/stable/core/reference/en/html/objectstate.html#objectstate-冲洗 – RMorrisey 2010-09-15 08:09:05