从HasMany与NHibernate的关系中读取未提交的数据

时间:2013-07-30 07:38:51

标签: nhibernate has-many unit-of-work read-uncommitted

我有一个NHibernate映射,它定义了一个类型的HasMany关系,即一个类有另一个类的列表。

我希望NHibernate能够读取未提交的数据,包括HasMany关系产生的列表。

我有隔离级别的ReadUncomitted,我可以在提交之前写入数据并将其读回。

但是,除非我先提交,否则列表始终为空。

有没有办法让NHibernate使用来自HasMany关系的数据填充对象?

修改

事实证明,除非实际将类添加到类中,否则类中的任何非基本类型都不会被 填充。

例如,下面的课程Foo有一个Member列表,其中 - 在数据库中 - 由Id连接。如果我使用NHibernate将Foo的实例和Member的实例持久保存到数据库,并且两者实际上都与Id的值相关,那么Foo 具有预期的Member实例。

public class Member
{
     Guid Id{ get; set; }
}

public class Foo
{
    List<Member> MemberList{ get; set; }
}

// the mapping
public class FooMap
{
    HasMany(x => x.MemberList).KeyColumn("Id").PropertyRef("Id");
}

但是,如果我创建Foo的实例和Member的实例并将后者设置为前者的引用并使用NHibermate将两者都保存到数据库,则Foo当我在完成交易之前将其读回时,拥有预期的Member实例。

如果我完成了该事务,那么Foo将在后续读取中具有预期的Member实例;只要事务完成,Member仅作为具有正确FK的数据库记录存在于Foo或者是Foo的引用是无关紧要的。

修订问题: 在未提交的读取期间,NHibernate可能仅基于 FK关系填充复杂成员吗?

2 个答案:

答案 0 :(得分:0)

当你实例化一个新对象时,它自然包含所有它的属性的默认值+通过构造函数设置的任何属性。

这意味着您必须查询您的实体对象才能获取其中的任何持久数据。

所以,例如如果我们有这两个类

public class Customer
{
    public virtual Guid Id { get; set; }
    public virtual ICollection<Order> Orders { get; set; }
}

public class Order
{
    public virtual Guid Id { get; set; }

    public virtual string Description { get; set; }
    //todo add items
}

然后我们需要这样一种方法:

public Customer GetCustomerWithUncommitedOrders(Guid customerId)
{
    ITransaction t = null;
    Customer customer = null;

    try
    {
        t = session.BeginTransaction(System.Data.IsolationLevel.ReadUncommitted);


        customer = session.QueryOver<Customer>().Where(x => x.Id == customerId).Fetch(x => x.Orders).Eager.List();


        t.Commit();
    }
    catch (Exception ex)
    {
        //todo log

        if (t != null)
            t.Rollback();
    }
    finally
    {
        if (t != null)
            t.Dispose();
    }

    return customer;
}

然后我们可以编辑客户,并将其保存在另一个(或相同的,取决于“编辑”持续时间)事务中。 但是,这可能会带来并发性的担忧。

答案 1 :(得分:0)

这里似乎存在一些普遍的混淆,所以要澄清一些事情:

  • 事务的隔离级别仅影响来自其他的更改 交易是可见的。事务总是可以回读它自己修改过的数据。

  • 如果接下来,对事务的Commit()调用是否与之无关 或者不拥有该事务的NHibernate会话可以回读这些更改 或不。它总是可以。

  • 但是,NHibernate不会修改已加载的实例。你,作为开发者 该模型,负责在加载的实体中进行更改,确保模型 仍然有效且符合您的业务规则,然后NHibernate会 将更改存储在DB中。建立模型的一部分是 NHibernate的工作 与你在另一部分所做的改变一致。

  • 在调用Commit()之前或之后回读并不重要,就像NHibernate一样 保证会话最多只包含每个实体的一个副本。所以当 你查询刚刚保存的对象,你就会回来一样 加载,未修改的实例。

  • 重要的是,如果您关闭会话并为查询打开新会话。然后 NHibernate将再次实例化该对象,它将反映当前状态 的数据库。如果使用,可以在原始会话中产生相同的效果 会话上的Clear()或Evict()(在调用Flush()或Commit()之后)。这些 方法从会话中删除已加载的实例,所以下次你 查询它,会话将创建一个新实例,当然这将反映当前事务中可见的数据库的当前状态。