Fluent Nhibernate - Mapping a list results in Null

2020-07-31 05:06发布

I have the following classes and fluent mappings:

  public class A {
    public virtual int Id { get; private set; }
    public virtual string MyString { get; set; }
    public virtual IList<B> MyChildren { get; set; }
 }

  public class B {
    public virtual int Id { get; private set; }
    public virtual DateTime TheDate { get; set; }
  }

  public sealed class AMap : ClassMap<A> {
    public AMap() {
      Id(x => x.Id).GeneratedBy.Native().UnsavedValue(0);
      Map(x => x.MyString);
      HasMany(x => x.MyChildren).AsList(x => x.Column("Ordinal")).KeyColumn("AId").Not.KeyNullable();
    }
  }

  public sealed class BMap : ClassMap<B> {
    public BMap() {
      Id(x => x.Id).GeneratedBy.Native().UnsavedValue(0);
      Map(x => x.TheDate);
    }
  }

This results in the following mapping for A:

  <class xmlns="urn:nhibernate-mapping-2.2" mutable="true" name="A" table="`A`">
    <id name="Id" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" unsaved-value="0">
      <column name="Id" />
      <generator class="native" />
    </id>
    <property name="MyString" type="AnsiString">
      <column name="MyString" length="150" not-null="true" />
    </property>
    <list name="MyChildren" mutable="true">
      <key not-null="true">
        <column name="AId" />
      </key>
      <index>
        <column name="Ordinal" />
      </index>
      <one-to-many class="B" />
    </list>
  </class>

But when I actually try to save an instance of A, I get a NullReferenceException:

System.NullReferenceException : Object reference not set to an instance of an object.
at NHibernate.Collection.PersistentList.GetSnapshot(ICollectionPersister persister)
at NHibernate.Engine.CollectionEntry..ctor(ICollectionPersister persister, IPersistentCollection collection)
at NHibernate.Engine.StatefulPersistenceContext.AddNewCollection(ICollectionPersister persister, IPersistentCollection collection)
at NHibernate.Event.Default.WrapVisitor.ProcessArrayOrNewCollection(Object collection, CollectionType collectionType)
at NHibernate.Event.Default.WrapVisitor.ProcessCollection(Object collection, CollectionType collectionType)
at NHibernate.Event.Default.AbstractVisitor.ProcessValue(Object value, IType type)
at NHibernate.Event.Default.WrapVisitor.ProcessValue(Int32 i, Object[] values, IType[] types)
at NHibernate.Event.Default.AbstractVisitor.ProcessEntityPropertyValues(Object[] values, IType[] types)
at NHibernate.Event.Default.AbstractSaveEventListener.VisitCollectionsBeforeSave(Object entity, Object id, Object[] values, IType[] types, IEventSource source)
at NHibernate.Event.Default.AbstractSaveEventListener.PerformSaveOrReplicate(Object entity, EntityKey key, IEntityPersister persister, Boolean useIdentityColumn, Object anything, IEventSource source, Boolean requiresImmediateIdAccess)
at NHibernate.Event.Default.AbstractSaveEventListener.PerformSave(Object entity, Object id, IEntityPersister persister, Boolean useIdentityColumn, Object anything, IEventSource source, Boolean requiresImmediateIdAccess)
at NHibernate.Event.Default.AbstractSaveEventListener.SaveWithGeneratedId(Object entity, String entityName, Object anything, IEventSource source, Boolean requiresImmediateIdAccess)
at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent event)
at NHibernate.Event.Default.DefaultSaveEventListener.SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent event)
at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.EntityIsTransient(SaveOrUpdateEvent event)
at NHibernate.Event.Default.DefaultSaveEventListener.PerformSaveOrUpdate(SaveOrUpdateEvent event)
at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.OnSaveOrUpdate(SaveOrUpdateEvent event)
at NHibernate.Impl.SessionImpl.FireSave(SaveOrUpdateEvent event)
at NHibernate.Impl.SessionImpl.Save(Object obj)

What am I doing wrong here?

Clarification: This is how I'm using the classes:

var a = new A { MyChildren = new List<B> { new B { TheDate = DateTime.Now } } };
a.MyChildren[0].Parent = a;

session.Save(a);

3条回答
SAY GOODBYE
2楼-- · 2020-07-31 05:15

You should add MyChildren = New List<B>(); to your constructor for A

查看更多
做自己的国王
3楼-- · 2020-07-31 05:17

Shouldn't your key column be "Id" (as opposed to "AId") for the child collection? I think that this is the source of your problem...

查看更多
Emotional °昔
4楼-- · 2020-07-31 05:31

I figured this out. The sample above actually does work, but the issue I was trying to reproduce was still running, causing the same error. Sorry about that...

The issue is that we had created this ChildList class, which we returned for the MyChildren property. It simply wrapped the List (or whatever concrete list NHibernate uses for persistent lists), but it took care of setting the Parent property on whatever instance was added or removed from the collection.

Apparently this causes NHibernate problems when saving even a new instance. Returning a normal concrete List works.

查看更多
登录 后发表回答