20

nulle ou transitoire Je reçois cette exception (exception complète en bas):NHibernate - propriété non-nulle référence une valeur

NHibernate.PropertyValueException was unhandled by user code 
Message="not-null property references a null or transient 
valueClearwave.Models.Encounters.Insurance.Patient" 
Source="NHibernate" 
EntityName="Clearwave.Models.Encounters.Insurance" 
PropertyName="Patient" 

Je l'ai fait beaucoup de recherches sur Google et il semble que le plus courant cause pour cette erreur est quand une association est bidirectionnelle mais seulement la moitié a été définie. Comme dans: Insurance.Patient = Patient est appelé mais Patient.Insurances.Add (assurance) n'est pas. J'ai, en fait, un scénario comme ça, mais j'ai vérifié l'objet juste avant d'appeler Enregistrer avec lui et à la fois Insurance.Patient et Patient.Insurances [0] sont les bons objets.

L'autre possibilité que cette exception semble faire référence est une valeur transitoire . Dans mon cas chaque objet est transitoire donc je suis suspect de la racine de mon problème est ici. Cependant, tout doit être transitoire en ce moment car rien n'a encore été sauvegardé. Je voudrais attendre NHibernate pour persister des choses plutôt que de se plaindre qu'ils sont pas persisté.

Voici quelques extraits de mes applications (courant):

 public PatientMap() 
     { 
      WithTable("tPatient"); 

      Id(x => x.Id, "uid_Patient").GeneratedBy.GuidComb 
().Access.AsReadOnlyPropertyThroughCamelCaseField(); 

      HasMany(x => x.Insurances).WithKeyColumn("uid_Patient") 
       .Cascade.All() 
       .Inverse(); 

      ... 
     } 

     public InsuranceMap() 
     { 
      WithTable("tPatientInsuranceInfo"); 

      Id(x => x.Id, 
"uid_PatientInsuranceInfo").GeneratedBy.GuidComb 
().Access.AsReadOnlyPropertyThroughCamelCaseField(); 

      References(x => x.Patient, "uid_Patient").Not.Nullable 
().Cascade.All(); 

      ... 
     } 

Alors, quel pourrait être le problème?


NHibernate.PropertyValueException was unhandled by user code 
Message="not-null property references a null or transient 
valueClearwave.Models.Encounters.Insurance.Patient" 
Source="NHibernate" 
EntityName="Clearwave.Models.Encounters.Insurance" 
PropertyName="Patient" 
StackTrace: 
     at NHibernate.Engine.Nullability.CheckNullability(Object[] 
values, IEntityPersister persister, Boolean isUpdate) 
     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.DefaultMergeEventListener.EntityIsTransient 
(MergeEvent event, IDictionary copyCache) 
     at NHibernate.Event.Default.DefaultMergeEventListener.OnMerge 
(MergeEvent event, IDictionary copyCache) 
     at NHibernate.Impl.SessionImpl.FireSaveOrUpdateCopy(IDictionary 
copiedAlready, MergeEvent event) 
     at NHibernate.Impl.SessionImpl.SaveOrUpdateCopy(String 
entityName, Object obj, IDictionary copiedAlready) 
     at 
NHibernate.Engine.CascadingAction.SaveUpdateCopyCascadingAction.Cascade 
(IEventSource session, Object child, String entityName, Object 
anything, Boolean isCascadeDeleteEnabled) 
     at NHibernate.Engine.Cascade.CascadeToOne(Object child, IType 
type, CascadeStyle style, Object anything, Boolean 
isCascadeDeleteEnabled) 
     at NHibernate.Engine.Cascade.CascadeAssociation(Object child, 
IType type, CascadeStyle style, Object anything, Boolean 
isCascadeDeleteEnabled) 
     at NHibernate.Engine.Cascade.CascadeProperty(Object child, 
IType type, CascadeStyle style, Object anything, Boolean 
isCascadeDeleteEnabled) 
     at NHibernate.Engine.Cascade.CascadeOn(IEntityPersister 
persister, Object parent, Object anything) 
     at 
NHibernate.Event.Default.AbstractSaveEventListener.CascadeBeforeSave 
(IEventSource source, IEntityPersister persister, Object entity, 
Object anything) 
     at 
NHibernate.Event.Default.DefaultMergeEventListener.EntityIsTransient 
(MergeEvent event, IDictionary copyCache) 
     at NHibernate.Event.Default.DefaultMergeEventListener.OnMerge 
(MergeEvent event, IDictionary copyCache) 
     at NHibernate.Impl.SessionImpl.FireSaveOrUpdateCopy(IDictionary 
copiedAlready, MergeEvent event) 
     at NHibernate.Impl.SessionImpl.SaveOrUpdateCopy(String 
entityName, Object obj, IDictionary copiedAlready) 
     at 
NHibernate.Engine.CascadingAction.SaveUpdateCopyCascadingAction.Cascade 
(IEventSource session, Object child, String entityName, Object 
anything, Boolean isCascadeDeleteEnabled) 
     at NHibernate.Engine.Cascade.CascadeToOne(Object child, IType 
type, CascadeStyle style, Object anything, Boolean 
isCascadeDeleteEnabled) 
     at NHibernate.Engine.Cascade.CascadeAssociation(Object child, 
IType type, CascadeStyle style, Object anything, Boolean 
isCascadeDeleteEnabled) 
     at NHibernate.Engine.Cascade.CascadeProperty(Object child, 
IType type, CascadeStyle style, Object anything, Boolean 
isCascadeDeleteEnabled) 
     at NHibernate.Engine.Cascade.CascadeOn(IEntityPersister 
persister, Object parent, Object anything) 
     at 
NHibernate.Event.Default.AbstractSaveEventListener.CascadeBeforeSave 
(IEventSource source, IEntityPersister persister, Object entity, 
Object anything) 
     at 
NHibernate.Event.Default.DefaultMergeEventListener.EntityIsTransient 
(MergeEvent event, IDictionary copyCache) 
     at NHibernate.Event.Default.DefaultMergeEventListener.OnMerge 
(MergeEvent event, IDictionary copyCache) 
     at NHibernate.Event.Default.DefaultMergeEventListener.OnMerge 
(MergeEvent event) 
     at NHibernate.Impl.SessionImpl.FireSaveOrUpdateCopy(MergeEvent 
event) 
     at NHibernate.Impl.SessionImpl.SaveOrUpdateCopy(Object obj) 
     at Clearwave.Models.Data.Util.RepositoryBase`2.Save(EntityType& 
entity) in C:\Projects\ClearWave\Src\Common\Domain Models 
\Clearwave.Models.Data-NHibernate\Util\RepositoryBase.cs:line 25 
     at IntegrationWebServices.FromMirth.SubmitMessage(Message 
theMessage, Guid providerOrganizationId) 
     at SyncInvokeSubmitMessage(Object , Object[] , Object[]) 
     at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke 
(Object instance, Object[] inputs, Object[]& outputs) 
     at 
System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin 
(MessageRpc& rpc) 
InnerException: 
+0

Pouvez-vous poster le code qui fait l'exception à être jeté. –

+0

Le code est patient = Session.SaveOrUpdateCopy (patient); Je pense que toute méthode ISession.Save le fait bien. – brendanjerwin

Répondre

16

Une autre possibilité est que vous enregistrez un graphe d'objet entier, et ce graphe est circulaire, et les éléments ne peuvent pas être nuls. Vous pourriez donner à NHibernate aucun ordre légal pour faire les insertions. (Il devrait produire un meilleur message d'erreur, mais il produit celui-ci).

Sans voir le reste de la source, il est difficile d'être plus utile. Essayez de supprimer les entités des mappages (et ne les enregistrez pas) jusqu'à ce que vous puissiez déterminer quelle est la cause du problème.

+1

Oui, exactement, en sauvant le graphique entier, il est circulaire, et les éléments ne peuvent pas être nulles. La seule façon de le persister est d'insérer des parties de l'entité, d'insérer d'autres entités, puis de revenir avec des mises à jour tout autour pour les connecter. NH ne peut tout simplement pas grok ce processus hein? – brendanjerwin

+0

Non. Si les éléments ne peuvent pas être null, il n'y a aucun moyen de faire le premier insert! NH ne rapporte pas une très belle erreur cependant. –

+3

Si vous définissez Cascade sur All() ou SaveUpdate() sur vos mappages patient, cela devrait fonctionner selon la suggestion de Sid, ci-dessous. –

0

Il ressemble à l'exception provient à la ligne 25 de votre fichier RepositoryBase.cs, probablement lors d'un enregistrement() est appelée sur un de vos objets transitoires. Lequel est en train d'être sauvé?

En outre, et il pourrait être sans rapport puisque je ne suis pas familier avec la syntaxe Fluent, devrait l'objet enfant (l'assurance dans ce cas) avoir .Cascade.All dessus? Dans la syntaxe de schéma XML standard, seul le mappage parent a cascade = "all" dans la collection d'objets enfants.

+0

L'objet Patient est en cours d'enregistrement. Que voulez-vous dire par «parent»? RE: Cascade = all? Le côté qui possède la relation (assurance) ou le propriétaire de l'autre entité (patient)? – brendanjerwin

+0

BTW, je l'ai eu pour arrêter de jeter l'exception en sauvant le patient avant de créer les objets d'assurance. De cette façon, le patient d'assurance n'a pas référé un objet transitoire. Cependant, cela me semble faux. NH ne devrait-il pas être en mesure de conserver un graphe d'objets entiers et de conserver les objectifs transitoires? – brendanjerwin

8

J'ai rencontré ce problème récemment et cela a à voir avec la façon dont les relations bidirectionnelles de NHibernate sont persistantes. Vous avez la cartographie correcte et donc NHibernate n'effectuera pas l'insertion du patient. Ensuite, NHibernate doit prendre la clé des patients et la castrer dans les assurances. Puisque le patient n'existe pas encore, les clés n'existent pas et il ne peut pas effectuer le deuxième insert. La clé est de définir la relation via le code avant la persistance, quelque chose comme ceci:

patient = new Patient(); 
patient.Insurances.Add(new Insurance{ Patient = patient }); 
repository.Save(patient); 

Maintenant, il était étranger à moi que vous devez définir la propriété des patients sur le point de collecte, mais si vous ignorez la persistance tous ensemble vous définirez ceci dans le code indépendamment de votre stratégie de persistance.

9

pas sûr si ça aide, mais cela l'a fait pour moi.

<many-to-one name="Company" column="CompanyId" cascade="all" not-null="true"/> 

cascade = "all" est ce que je manqué avant

+1

Merci, ça a marché pour moi. –

+0

J'utilise Entity Developer pour générer les mappages, et la définition de la propriété Cascade sur l'entité associée a été le problème pour moi – hanzolo

1

Cela a fonctionné pour moi. Les choses importantes ici sont que nous avons References avec Cascade.All() et nous n'avons pas Inverse() sur HasMany

public PatientMap() 
{ 
    HasMany(x => x.Insurances) 
     .WithKeyColumn("uid_Patient") 
     .Cascade.All(); 

    ... 
} 

public InsuranceMap() 
{ 
    References(x => x.Patient, "uid_Patient") 
     .Not.Nullable() 
     .Cascade.All(); 

    ... 
}