为什么NHibernate会抛出一个;GenericADOException:无法初始化集合";ISession期间出现异常。在这种情况下是否刷新?

为什么NHibernate会抛出一个;GenericADOException:无法初始化集合";ISession期间出现异常。在这种情况下是否刷新?,nhibernate,nhibernate-mapping,lazy-loading,Nhibernate,Nhibernate Mapping,Lazy Loading,我在ISession.Refresh() 我有一个具有延迟加载的子集合的实体,以及一个命中此集合的只读属性,所有这些都包含在二级缓存中。 我在长会话中使用ISession.Refresh(),在将事务提交到DB后获取最新数据,并得到以下错误: NHibernate.Exceptions.GenericADOException : could not initialize a collection: [Test.NUnit.DBTest.TestModel.ParentTestEntity.Chi

我在
ISession.Refresh()

我有一个具有延迟加载的子集合的实体,以及一个命中此集合的只读属性,所有这些都包含在二级缓存中。 我在长会话中使用
ISession.Refresh()
,在将事务提交到DB后获取最新数据,并得到以下错误:

NHibernate.Exceptions.GenericADOException : could not initialize a collection: [Test.NUnit.DBTest.TestModel.ParentTestEntity.Children#d4251363-cf88-4684-b65a-9f330107afcf][SQL: SELECT children0_.ParentTestEntity_id as ParentTe4_1_, children0_.Id as Id1_, children0_.Id as Id42_0_, children0_.RowVersion as RowVersion42_0_, children0_.Parent_id as Parent3_42_0_ FROM "ChildTestEntity" children0_ WHERE children0_.ParentTestEntity_id=?]
  ----> System.NullReferenceException : Object reference not set to an instance of an object.
    at NHibernate.Loader.Loader.LoadCollection(ISessionImplementor session, Object id, IType type)
    at NHibernate.Loader.Collection.CollectionLoader.Initialize(Object id, ISessionImplementor session)
    at NHibernate.Persister.Collection.AbstractCollectionPersister.Initialize(Object key, ISessionImplementor session)
    at NHibernate.Event.Default.DefaultInitializeCollectionEventListener.OnInitializeCollection(InitializeCollectionEvent event)
    at NHibernate.Impl.SessionImpl.InitializeCollection(IPersistentCollection collection, Boolean writing)
    at NHibernate.Collection.AbstractPersistentCollection.Initialize(Boolean writing)
    at NHibernate.Collection.AbstractPersistentCollection.ReadSize()
    at NHibernate.Collection.PersistentBag.get_Count()
    DBTest\TestModel\EntiteTestCacheCollectionsParent.cs(25,0): at Test.NUnit.DBTest.TestModel.ParentTestEntity.get_Count()
    at (Object , GetterCallback )
    at NHibernate.Bytecode.Lightweight.AccessOptimizer.GetPropertyValues(Object target)
    at NHibernate.Tuple.Entity.PocoEntityTuplizer.GetPropertyValuesWithOptimizer(Object entity)
    at NHibernate.Tuple.Entity.PocoEntityTuplizer.GetPropertyValues(Object entity)
    at NHibernate.Persister.Entity.AbstractEntityPersister.GetPropertyValues(Object obj, EntityMode entityMode)
    at NHibernate.Event.Default.AbstractVisitor.Process(Object obj, IEntityPersister persister)
    at NHibernate.Event.Default.DefaultRefreshEventListener.OnRefresh(RefreshEvent event, IDictionary refreshedAlready)
    at NHibernate.Event.Default.DefaultRefreshEventListener.OnRefresh(RefreshEvent event)
    at NHibernate.Impl.SessionImpl.FireRefresh(RefreshEvent refreshEvent)
    at NHibernate.Impl.SessionImpl.Refresh(Object obj)
    DBTest\NHibernateBehaviorTests.cs(610,0): at Test.NUnit.DBTest.NHibernateBehaviorTests.Test()
    --NullReferenceException
    at NHibernate.Engine.Loading.CollectionLoadContext.AddCollectionToCache(LoadingCollectionEntry lce, ICollectionPersister persister)
    at NHibernate.Engine.Loading.CollectionLoadContext.EndLoadingCollection(LoadingCollectionEntry lce, ICollectionPersister persister)
    at NHibernate.Engine.Loading.CollectionLoadContext.EndLoadingCollections(ICollectionPersister persister, IList`1 matchedCollectionEntries)
    at NHibernate.Engine.Loading.CollectionLoadContext.EndLoadingCollections(ICollectionPersister persister)
    at NHibernate.Loader.Loader.EndCollectionLoad(Object resultSetId, ISessionImplementor session, ICollectionPersister collectionPersister)
    at NHibernate.Loader.Loader.InitializeEntitiesAndCollections(IList hydratedObjects, Object resultSetId, ISessionImplementor session, Boolean readOnly)
    at NHibernate.Loader.Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies)
    at NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies)
    at NHibernate.Loader.Loader.LoadCollection(ISessionImplementor session, Object id, IType type)
下面是一个单元测试,它显示了简化模型的问题:

    [Test]
    public void Test()
    {
        ISession session1 = NHibernateHelper.SessionFactory.OpenSession();
        ISession session2 = NHibernateHelper.SessionFactory.OpenSession();

        // Create a new entity tree and persist it
        ParentTestEntity parentSession1 = new ParentTestEntity();
        parentSession1.AddChild(new ChildTestEntity());
        session1.Save(parentSession1);
        session1.Flush();

        // Load the saved object into another session
        ParentTestEntity parentSession2 = session2.Get<ParentTestEntity>(parentSession1.Id);
        session2.Refresh(parentSession2); // Throws here
    }
[测试]
公开无效测试()
{
ISession session1=NHibernateHelper.SessionFactory.OpenSession();
ISession session2=NHibernateHelper.SessionFactory.OpenSession();
//创建一个新的实体树并将其持久化
ParentTestEntity parentSession1=新的ParentTestEntity();
parentSession1.AddChild(newChildTestEntity());
session1.Save(parentSession1);
session1.Flush();
//将保存的对象加载到另一个会话中
ParentTestEntity parentSession2=session2.Get(parentSession1.Id);
session2.Refresh(parentSession2);//在此处抛出
}
以下是涉及的实体:

public class ParentTestEntity
{
    public virtual Guid Id { get; private set; }
    public virtual long RowVersion { get; private set; }

    public virtual IList<ChildTestEntity> Children { get; protected set; }

    public ParentTestEntity()
    {
        this.Children = new List<ChildTestEntity>();
    }

    public virtual int Count
    {
        get
        {
            return Children.Count;
        }

        set { }
    }

    public virtual void AddChild(ChildTestEntity child)
    {
        if (this.Children == null)
        {
            this.Children = new List<ChildTestEntity>();
        }

        this.Children.Add(child);
        child.Parent = this;
    }
}

public class ChildTestEntity
{
    public virtual Guid Id { get; private set; }
    public virtual long RowVersion { get; private set; }

    public virtual ParentTestEntity Parent { get; set; }
}
公共类ParentTestEntity
{
公共虚拟Guid Id{get;private set;}
公共虚拟长行版本{get;private set;}
公共虚拟IList子项{get;protected set;}
公共ParentTestEntity()
{
this.Children=新列表();
}
公共虚拟整数计数
{
得到
{
返回儿童。计数;
}
集合{}
}
公共虚拟void AddChild(ChildTestEntity子项)
{
if(this.Children==null)
{
this.Children=新列表();
}
this.Children.Add(child);
child.Parent=this;
}
}
公营儿童福利机构
{
公共虚拟Guid Id{get;private set;}
公共虚拟长行版本{get;private set;}
公共虚拟ParentTestEntity父项{get;set;}
}
及其映射:

public class ParentTestEntityMap : ClassMap<ParentTestEntity>
{
    public ParentTestEntityMap()
    {
        Cache.ReadWrite();

        Id(x => x.Id)
            .GeneratedBy.GuidComb();

        Version(x => x.RowVersion);

        HasMany(x => x.Children)
            .Inverse()
            .Cascade.All()
            .Cache.ReadWrite();

        Map(x => x.Count);
    }
}

public class ChildTestEntityMap : ClassMap<ChildTestEntity>
{
    public ChildTestEntityMap()
    {
        Cache.ReadWrite();

        Id(x => x.Id)
            .GeneratedBy.GuidComb(); 

        Version(x => x.RowVersion);

        References(x => x.Parent)
            .Not.Nullable();
    }
}
公共类ParentTestEntityMap:ClassMap { 公共ParentTestEntityMap() { Cache.ReadWrite(); Id(x=>x.Id) .GeneratedBy.GuidComb(); 版本(x=>x.RowVersion); 有很多(x=>x个孩子) .Inverse() .Cascade.All() .Cache.ReadWrite(); Map(x=>x.Count); } } 公共类ChildTestEntityMap:ClassMap { 公共儿童测试地图() { Cache.ReadWrite(); Id(x=>x.Id) .GeneratedBy.GuidComb(); 版本(x=>x.RowVersion); 引用(x=>x.Parent) .Not.Nullable(); } }
在我的测试中,我发现:

  • 正在删除
    Count
    属性的映射
  • 正在删除
    缓存.ReadWrite()
    映射
  • 在刷新之前枚举集合
足够
刷新
正常工作

有人知道我能做些什么来更新工作吗

注:

  • 我可以在NHibernate 2.1.2和3.1.0中重现这种行为
  • 我知道
    Count
    中的空setter很难看,它在这里只是为了反映真实模型中实体的映射
    • 请参阅。我不会在这里详述所有细节,因为你可以在那里阅读

      简单的回答是,您正在访问构造函数中的虚拟属性,这是不允许的。下面的更改应该可以解决这个问题。更换这些线路

      public virtual IList<ChildTestEntity> Children { get; protected set; }
      
      public ParentTestEntity()
      {
          this.Children = new List<ChildTestEntity>();
      }
      
      public虚拟IList子项{get;protected set;}
      公共ParentTestEntity()
      {
      this.Children=新列表();
      }
      
      。。。以下几行:

      private IList<ChildTestEntity> _children;
      
      public virtual IList<ChildTestEntity> Children
      {
          get { return _children; }
          protected set { _children = value; }
      }
      
      public ParentTestEntity()
      {
          _children = new List<ChildTestEntity>();
      }
      
      private IList\u儿童;
      公共虚拟现实主义儿童
      {
      获取{return\u children;}
      受保护集{u children=value;}
      }
      公共ParentTestEntity()
      {
      _children=新列表();
      }
      
      FxCop和ReSharper是两种不同的工具,可以自动识别此问题。

      使用
      Load()
      替换
      Get()
      cirucmv解决此问题

      这不是一个通用的解决方案,因为
      Load()
      的语义稍有不同,如果对应的行不存在,就会抛出

      不过,这在我们的体系结构中是一个可接受的约束,因为我们知道加载的实体存在于数据库中


      但是,仍然欢迎使用
      Get()
      的任何解决方案。

      没错,这是模型中一个糟糕的设计疏忽(我知道规则,但当时没有想到,谢谢提醒我)。然而,这与问题无关;测试失败的方式与您的更改完全相同。它似乎更多地与计数的getter相关联,如堆栈跟踪所示。