2011-08-02 17 views
7

ISession.Refresh() ile garip bir davranış (en azından benim için) yaşıyorum.Niçin NHibernate bu durumda ISession.Refresh sırasında bir "GenericADOException: bir koleksiyon başlatılamadı" özel durumu atar?

Tembel yüklü bir çocuk koleksiyonuna sahip bir varlık var ve bu koleksiyona isabet eden salt okunur bir özellik var, hepsi de 2. düzey önbellek dahil. DB'den bir işlem yapılıyor sonra son verileri almak ve aşağıdaki hatayı almak için uzun bir oturumda ISession.Refresh() kullanın:

: Burada

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) 

basitleştirilmiş modeli ile sorunu göstermek bir birim testidir

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; } 
} 

Ve onların eşleştirmeleri:

İşte

[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 
    } 
katılan kuruluşlardır Benim testleri sırasında

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(); 
    } 
} 
onu da bulundu:

  • , Refresh önce toplanmasını numaralandırma Cache.ReadWrite() eşleştirmeleri çıkarmadan Count mülkiyet eşleştirmesini,
  • ,
  • çıkarmadan

Refresh'un doğru çalışması için yeterlidir.

Refresh çalışması için neler yapabileceğimi bilen var mı?

Notlar: NHibernate 2.1.2 ve 3.1.0 hem bu davranışı üretebilir

  • , ben Count boş ayarlayıcı çirkin olduğunu biliyorum
  • , sadece bir eşleme ayna burada gerçek modeldeki varlık.

cevap

1

Load()'un kullanılması, Get()'un yerine geçer.

Bu, genel bir çözüm değildir; Load(), biraz farklı anlamlara sahiptir ve karşılık gelen satır yoksa, atılır.

Bu, mimarilerimizde yüklü olan girdilerin DB'de var olduğunu bildiğimiz gibi kabul edilebilir bir kısıtlamadır. Bununla birlikte, Get() ile herhangi bir çözüm, yine de memnuniyetle karşılanabilir.

0

Lütfen my answer for a similar question, "Cannot assign property value in entity's constructor"'a bakın. Burada tüm detaylara girmeyeceğim çünkü orada okuyabilirsiniz.

Kısa cevap, yapıcınızdaki sanal bir özelliğe erişmenizdir, ki bu bir hayır-hayır. Aşağıdaki değişiklik sorunu çözmelidir. Bu satırların ile ... ...

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

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

bu satırları değiştirin:

private IList<ChildTestEntity> _children; 

public virtual IList<ChildTestEntity> Children 
{ 
    get { return _children; } 
    protected set { _children = value; } 
} 

public ParentTestEntity() 
{ 
    _children = new List<ChildTestEntity>(); 
} 

FxCop ve ReSharper otomatik olarak bu sorunu tanımlamak iki farklı araç vardır.

+0

Doğru, bu modelde kötü bir tasarım denetimi (kuralı biliyordum, ama o zamanlar hakkında düşünmedim, bana hatırlattığın için teşekkürler). Bu sorunla bağlantılı değil; Test, değişikliklerinizle aynı şekilde başarısız olur. Yığın izinin gösterdiği gibi Sayım alıcısıyla daha bağlantılı görünüyor. –

İlgili konular