验证NHibernate是否延迟加载了多对一属性

时间:2011-02-01 14:11:11

标签: nhibernate nhibernate-mapping lazy-loading

我有一个项目和一个人(有点简化):

public class Project
{
    public virtual Person CreatedBy { get; set; }
}

public class Person
{
    public virtual string Username { get; set; }
}

我正在接受NH Linq的项目:

var projects = from p in session.Query<Project>()
             select p;
var project = projects.First();

有时使用Fetch()

var project = projects.Fetch(p => p.CreatedBy).First();

现在,如何在单元测试中验证该项目.CreatedBy 急切加载(反之),具体取决于Fetch()是否为用过的?根据我的理解,使用Fetch()应该急切加载Person,如果我不使用Fetch(),它应该延迟加载Person。

我试过

Assert.IsTrue(NHibernateUtil.IsInitialized(project.CreatedBy));

并且

NHibernateUtil.IsPropertyInitialized(project, "CreatedBy")

但无论我是否使用Fetch(),它们都返回true。 IsInitialized()适用于集合(一对多),例如Person.Projects,但不适用于多对一...

CreatedBy属性应该是延迟加载的,但有时我希望它被急切加载,我希望单元测试确认它正在按预期工作。

CreatedBy属性的映射是

<many-to-one name="CreatedBy" class="Person" fetch="select">
  <column name="PERSON_ID" precision="10" scale="0" not-null="true" />
</many-to-one>

我验证了这样的映射:

var to1 = NHibernateConfiguration.GetClassMapping(typeof(Project))
    .ReferenceablePropertyIterator.FirstOrDefault(p => p.Name == "CreatedBy")
    .Value as NHibernate.Mapping.ToOne;

Assert.IsTrue(to1.IsLazy);
Assert.IsFalse(to1.UnwrapProxy);

哪个过去了。

有什么想法吗?

2 个答案:

答案 0 :(得分:5)

如果NHibernateUtil.IsInitialized(project.CreatedBy)返回true,那是因为它已初始化。

如果已经在会话中加载了Person,那么无论您是否急切地获取CreatedBy,它都将被初始化,这要归功于Identity Map。

答案 1 :(得分:-1)

我看到的一个解决方案如下:

而不是使用自动属性,    对于CreatedBy,使用'经典    property',它使用支持    字段,像这样:

private Person _createdBy;

public Person CreatedBy
{
    get { return _createdBy; }
    set { _createdBy = value; }
}

在映射文件中,指示NHibernate应使用支持字段,而不是属性:

<many-to-one name="CreatedBy" class="Person" access="field.camelcase-underscore" fetch="select">
  <column name="PERSON_ID" precision="10" scale="0" not-null="true" />
</many-to-one>

然后,您可以做的最美妙的事情是在单元测试项目中创建一个扩展方法,检查_createdBy字段是否已初始化。

很遗憾,您无法使用扩展方法访问私有成员。

因此,我认为您可以在Project类上创建一个内部方法,用于检查_createdBy字段是否已初始化。 您还应该使用[InternalsVisibleTo][1]属性,以便包含您的单元测试的项目可以访问Project类中的内部方法。

public class Project
{
     private Person _createdBy;

     public Person CreatedBy
     {
        get{return _createdBy;}
        set{ _createdBy = value; }
     }

     internal IsCreatedByInitialized()
     {
          return _createdBy != null;
     }
}

在您的单元测试中,您可以这样做:

Assert.IsTrue (p.isCreatedByInitialized());

请注意,如果您的单元测试位于单独的项目中,则需要指明该程序集应该可以访问内部方法: 因此,在AssemblyInfo.cs类所在的项目的Project文件中,您应该这样做:

[InternalsVisibleTo ("MyTestProject")]