NHibernate - not-null property reference a null or transient value
Asked Answered
A

5

24

I'm getting this exception (Full exception at the bottom):

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"

I've done a lot of Googling and it seems the most common cause for that error is when an association is bi-directional but only one half has been set. As in: Insurance.Patient = Patient is called but Patient.Insurances.Add(Insurance) is not. I do, in fact, have a scenario like that but I've checked the object just before calling Save with it and both Insurance.Patient and Patient.Insurances[0] are the right objects.

The other possibility that this exception seems to reference is a transient value. In my case every object is transient so I'm suspecting the root of my problem is here. However, everything needs to be transient right now because nothing has been saved yet. I would expect NHibernate to persist things rather than complain that they are not persisted.

Here are some snippets from my mappings (fluent):

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

           ...
        }

So, what could be the issue?


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:
Auto answered 20/2, 2009 at 2:9 Comment(2)
Could you post the code that causes the exception to be thrown.Kenwrick
The code is patient = Session.SaveOrUpdateCopy(patient); I think any ISession.Save method does it though.Auto
C
19

Another possibility is that you're saving an entire object graph, and that graph is circular, and items cannot be null. You could be giving NHibernate no legal order in which to do the inserts. (It should produce a better error message, but it produces this one).

Without seeing the rest of the source, it's hard to be of more help. Try removing entities from the mappings (and not saving them) until you can figure out what is causing the problem.

Carton answered 21/2, 2009 at 14:33 Comment(3)
Yes, exactly, saving the entire graph, it is circular, and items can not be null. The only way to persist it is to insert some parts of the entity, insert some other entities and then go back with updates all around to connect them. NH just can't grok that process huh?Auto
Nope. If the items can't be null, there is no way to do the first insert! NH doesn't report a very nice error though.Carton
If you set Cascade to All() or SaveUpdate() on your Patient mappings then this should work as per Sid's suggestion, below.Unremitting
H
10

not sure if it helps but this did it for me.

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

cascade="all" was what I missed out before

Hoyden answered 31/7, 2010 at 17:40 Comment(1)
I'm using Entity Developer to generate the mappings, and setting the Cascade property on the related entity was the issue for meJuliusjullundur
M
8

I've had this problem recently and it has to do with the way NHibernate bi-directional relationships are persisted. You have the mapping correct and therefore NHibernate will perform the Patient insert no problem. Then NHibernate needs to take the key from Patients and cascade that into Insurances. Since the Patient does not yet exist, the keys do not exist and it cannot perform the second insert. The key is to set the relationship via code prior to persistence, something like this:

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

Now it was foreign to me that you have to set the Patient property on the collection item, but if you ignore persistence all together you will be setting this in code independent of your persistence strategy.

Manservant answered 6/10, 2009 at 21:20 Comment(0)
M
1

This worked for me. The important things here are that we have References with Cascade.All() and we don't have Inverse() on HasMany

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

    ...
}

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

    ...
}
Metamorphic answered 13/5, 2016 at 17:55 Comment(0)
K
0

It looks like the exception originates at line 25 of your RepositoryBase.cs file, presumably when a Save() is called on one of your transient objects. Which one is being saved?

Also, and it might be unrelated since I'm unfamiliar with the Fluent syntax, should the child object (the insurance in this case) have .Cascade.All on it? In standard XML schema syntax, only the parent mapping has cascade="all" on the collection of child objects.

Kaleena answered 20/2, 2009 at 14:45 Comment(2)
The Patient object is being saved. What do you mean by "parent" RE: Cascade=all? The side that owns the relationship (insurance) or the owner of the other entity (patient)?Auto
BTW, I got it to stop throwing the exception by saving the patient before creating the insurance objects. That way the Insurance.Patient did not reference a transient object. However, that seems wrong to me. Shouldn't NH be able to persist a whole object graph and know to persist the transient objs?Auto

© 2022 - 2024 — McMap. All rights reserved.