2010-08-05 15 views
1

Je les classes et les applications couramment suivantes:Fluent Nhibernate - Mapper une liste donne NullReferenceException?

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

Il en résulte la mise en correspondance suivante 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> 

Mais quand j'essaie en fait d'enregistrer une instance de A, je reçois un 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) 

Qu'est-ce que je fais mal ici?

Précision: Voici comment j'utilise les classes:

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

session.Save(a); 
+1

Pouvez-vous également publier le mappage généré pour la classe 'B'? – DanP

+0

Les joies d'une interface fluide, À VOTRE FACE! ; P – leppie

Répondre

0

Je l'ai compris. L'exemple ci-dessus fonctionne réellement, mais le problème que j'essayais de reproduire était toujours en cours, causant la même erreur. Désolé à ce sujet ...

Le problème est que nous avions créé cette classe ChildList, que nous avons renvoyée pour la propriété MyChildren. Il a simplement enveloppé la liste (ou toute autre liste concrète utilisée par NHibernate pour les listes persistantes), mais il a pris soin de définir la propriété Parent sur l'instance ajoutée ou retirée de la collection.

Apparemment, cela provoque des problèmes NHibernate lors de l'enregistrement même d'une nouvelle instance. Le retour d'une liste concrète normale fonctionne.

+0

Pensez à lire http://www.lostechies.com/blogs/jimmy_bogard/archive/2010/03/10/strengthening-your-domain-encapsulated-collections.aspx pour des conseils dans ce domaine. – DanP

+0

À droite, le problème est que vous vous retrouvez avec des tonnes de code de plaque de chaudière qui ne devraient pas être écrites tout le temps, et la solution dans l'article ne résout pas vraiment le problème de toute façon (comme en témoignent les nombreux commentaires d'autres problèmes). Personnellement, je crois que c'est la raison pour laquelle un ORM ne devrait pas être utilisé directement dans vos BO, mais cette décision ne m'appartient pas à moi seul. – Andy

1

Vous devez ajouter MyChildren = New List<B>(); à votre constructeur A

+0

J'ai essayé ça, ça n'a aucun effet. – Andy

0

ne devrait pas votre colonne clé est « Id » (par opposition à "AId") pour la collection enfant? Je pense que c'est la source de votre problème ...

+0

Non, cela fonctionne bien. AId est le nom du FK dans la table B. – Andy