NHibernate 4子集合已保存,但未重新加载

时间:2017-09-30 01:01:16

标签: nhibernate

我有一个NHibernate 4项目,有几个收集关系。我正在对对象模型进行单元测试,运用所有集合。大多数工作正常,但在一种情况下,子集合是正确级联保存的,但在加载父实体和检查集合属性时,子集合是空的。

这是缩写的类。 GatewayUser是父对象,它有一个Student集合。该集合具有私有支持属性和AddStudent / RemoveStudent方法。

进一步的复杂化:我正在使用NHibernate.AspNet.Identity库进行OAuth2用户管理,而GatewayUser继承自IdentityUser。这反过来继承自库的内部基本实体类,这与我项目自己的基类不同。

公共类GatewayUser:IdentityUser     {         public GatewayUser()         {         }

    public virtual string FirstName { get; set; }
    // ...More value properties and OAuth stuff omitted

    // students associated with this user
    private IList<Student> _students = new List<Student>();

    public virtual IList<Student> Students
    {
        get { return new ReadOnlyCollection<Student>(_students); }
    }

    public virtual GatewayUser AddStudent(Student s)
    {
        if (_students.Contains(s))
            return this;

        s.GatewayUser = this;
        _students.Add(s);
        return this;
    }

    public virtual GatewayUser RemoveStudent(Student s)
    {
        if (_students.Contains(s))
        {
            _students.Remove(s);
        }
        return this;
    }

学生更平凡;它继承自我自己的BaseEntity类,具有许多值属性,以及它自己的ProgramApplication项的子集合。有趣的是,这个系列节省并装载精细;它与GatewayUser中的失败集合具有相同的结构(私有支持者等)。

映射很复杂,因为库内部使用NHiberante.Mapping.ByCode.Conformist类(我以前没有经验)来映射它的类。 我正在使用NHibernate自动映射我自己的类,因为我有很多类和属性要映射。为了使它全部工作,我复制了库的映射助手类,并对其进行了一些修改,将我的基本实体类添加到名为baseEntityToIgnore的列表中。我还必须为GatewayUser创建一个一致的映射,因为它有一个不同的基本实体类型,而且我的自动化不会接收它。

单元测试如下:

    [Test]
    public void GatewayUserCascadesStudents()
    {

        var u = new GatewayUser() { FirstName = "Mama", LastName = "Bear", UserName = "somebody@example.com" };
        var s1 = new Student() { FirstName = "First", LastName = "Student" };
        var s2 = new Student() { FirstName = "Second", LastName = "Student" };

        u.AddStudent(s1).AddStudent(s2);

        using (var s = NewSession())
        using (var tx = s.BeginTransaction())
        {
            s.Save(u);
            tx.Commit();
        }

        GatewayUser fetched = null;
        int count = 0;
        using (var s = NewSession())
        {
            fetched = s.Get<GatewayUser>(u.Id);
            count = fetched.Students.Count;
        }

        Assert.AreEqual(2, count);
    }

生成的SQL插入AspNetUsers和GatewayUser(反映继承关系),并将两条记录插入Student。都好。在获取时,SELECT连接两个用户表,我得到一个GatewayUser对象,但访问Students集合不会触发Student表上的SELECT。但是,如果我将映射更改为Lazy(CollectionLazy.NoLazy),则选择急切加载的SQL将显示在日志中,但不会填充该集合。如果我将数据库从SQLite切换到Sql Server,我会在表中看到学生记录。生成的SQL(应用NoLazy时)将获取它们。所以在数据库端,事情看起来很好。

我必须认为我的弗兰肯斯坦映射情况是罪魁祸首。我正在将库的符合映射与Fluent映射混合,并且有两个不同的基本实体类。但是,生成的模式看起来正确,并且保存级联正确,所以我不知道这是否是问题。

1 个答案:

答案 0 :(得分:0)

找到我自己的答案。我对父类列表的映射是这样的:

public class GatewayUserMap:JoinedSubclassMapping     {         public GatewayUserMap()         {             键(g =&gt; g.Column(“Id”));             属性(c =&gt; c.FirstName,m =&gt; m.Length(50));             // ...更多属性

        List(gu => gu.Students, map =>
        {
            map.Key(c => c.Column("GatewayUser_Id"));
            map.Cascade(Cascade.All | Cascade.DeleteOrphans);
            map.Index(li => li.Column("ListIndex"));
            map.Access(Accessor.Field | Accessor.NoSetter);
        }
        );
    }
}

我有一个私人支持字段用于集合。从集合映射中删除Accessor.NoSetter修复它。实际上,它仍然可以在没有Accessor.Field的情况下工作 - 我猜映射器可以很好地查找一个,如果找到则使用它。将私有支持者的名称从“_students”更改为“funnyName”会阻止映射器查找它。