我有一个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关系填充复杂成员吗?
答案 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()之后)。这些 方法从会话中删除已加载的实例,所以下次你 查询它,会话将创建一个新实例,当然这将反映当前事务中可见的数据库的当前状态。