NHibernate - 非空属性引用空值或瞬态值

Posted

技术标签:

【中文标题】NHibernate - 非空属性引用空值或瞬态值【英文标题】:NHibernate - not-null property reference a null or transient value 【发布时间】:2010-10-08 18:09:16 【问题描述】:

我得到了这个异常(底部的完整异常):

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"

我用谷歌搜索了很多,这似乎是最常见的原因 该错误是关联是双向的但只有一半 已经设置好了。如: Insurance.Patient = Patient 被调用但 Patient.Insurances.Add(Insurance) 不是。事实上,我确实有一个 像这样的场景,但我在调用之前检查了对象 保存它,Insurance.Patient 和 Patient.Insurances[0] 都是 正确的对象。

此异常似乎引用的另一种可能性是 瞬态值。在我的情况下,每个对象都是瞬态的,所以我是 怀疑我的问题的根源在这里。然而,一切都需要 现在是暂时的,因为还没有保存任何内容。我会 期望 NHibernate 坚持事情而不是抱怨他们是 没有持久化。

以下是我的映射中的一些 sn-ps(流利):

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

           ...
        

那么,可能是什么问题?


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:

【问题讨论】:

您能否发布导致引发异常的代码。 代码是patient = Session.SaveOrUpdateCopy(patient);我认为任何 ISession.Save 方法都可以做到。 【参考方案1】:

另一种可能性是您正在保存整个对象图,并且该图是圆形的,并且项目不能为空。您可能没有给 NHibernate 提供执行插入的法律命令。 (它应该会产生更好的错误消息,但它会产生这个)。

如果不查看源的其余部分,很难获得更多帮助。尝试从映射中删除实体(而不是保存它们),直到找出导致问题的原因。

【讨论】:

是的,没错,就是保存整个图,是循环的,item不能为空。保持它的唯一方法是插入实体的某些部分,插入一些其他实体,然后返回周围的更新以连接它们。 NH 就是无法理解这个过程吧? 不。如果项目不能为空,则无法进行第一次插入!不过 NH 并没有报告一个非常好的错误。 如果您在 Patient 映射上将 Cascade 设置为 All() 或 SaveUpdate(),那么这应该按照 Sid 的建议工作,如下所示。【参考方案2】:

不确定它是否有帮助,但这对我有用。

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

cascade="all" 是我之前错过的

【讨论】:

我正在使用 Entity Developer 生成映射,而在相关实体上设置 Cascade 属性对我来说是个问题【参考方案3】:

我最近遇到了这个问题,它与 NHibernate 双向关系的持久化方式有关。您的映射正确,因此 NHibernate 将执行 Patient insert 没有问题。然后 NHibernate 需要从患者那里获取密钥并将其级联到保险中。由于 Patient 尚不存在,因此密钥不存在,因此无法执行第二次插入。关键是在持久化之前通过代码设置关系,如下所示:

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

现在,您必须在集合项上设置 Patient 属性对我来说很陌生,但是如果您一起忽略持久性,您将在代码中独立于持久性策略进行设置。

【讨论】:

【参考方案4】:

这对我有用。这里重要的是我们有ReferencesCascade.All() 而我们在HasMany 上没有Inverse()

public PatientMap()

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

    ...


public InsuranceMap()

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

    ...

【讨论】:

【参考方案5】:

看起来异常源自您的 RepositoryBase.cs 文件的第 25 行,大概是在您的一个瞬态对象上调用 Save() 时。哪一个得救了?

另外,由于我不熟悉 Fluent 语法,它可能不相关,子对象(在这种情况下是保险)是否应该有 .Cascade.All ?在标准 XML 模式语法中,只有父映射在子对象集合上具有 cascade="all"。

【讨论】:

正在保存患者对象。 “父母”是什么意思 RE:Cascade = all?拥有关系的一方(保险)或其他实体的所有者(患者)? 顺便说一句,我通过在创建保险对象之前保存患者来停止抛出异常。这样,Insurance.Patient 就没有引用瞬态对象。但是,这对我来说似乎是错误的。 NH 不应该能够持久化整个对象图并知道持久化瞬态对象吗?

以上是关于NHibernate - 非空属性引用空值或瞬态值的主要内容,如果未能解决你的问题,请参考以下文章

Grails - 非空属性引用空值或瞬态值

Grails - 非空属性仅对并发用户引用空值或瞬态值错误

Spring 和 Hibernate 错误——非空属性引用空值或瞬态值:com.tharaka.model.Employee.designation

插入时 NHibernate 组件非空属性

非空属性引用瞬态值 - 瞬态实例必须在当前操作之前保存

NHibernate 中的自引用实体给对象引用一个未保存的瞬态实例异常