1

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

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

我有隔离级别 ReadUncommitted 并且我能够在提交之前写入数据并读回它。

但是,列表总是空的,除非我先提交。

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

编辑

事实证明,类上的任何非原始类型都不会被未提交的读取填充,除非它们实际上被添加到类中。

例如,Foo下面的类有一个列表Member- 在数据库中 - 由Id. 如果我使用NHibernate将一个实例Foo和一个实例持久化到数据库中,Member并且两者实际上都与IdFooMember

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 关系填充复杂成员?

4

2 回答 2

1

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

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

  • 如果遵循事务的 Commit() 调用与拥有该事务的 NHibernate 会话是否可以读回这些更改无关。它总是可以的。

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

  • 在调用 Commit() 之前或之后回读并不重要,因为 NHibernate 保证会话最多只包含每个实体的一个副本。因此,当您查询刚刚保存的对象时,您将返回相同的、已加载的、未修改的实例。

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

于 2013-08-11T22:05:15.773 回答
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;
}

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

于 2013-07-30T08:21:23.523 回答