我有一个计划(不需要字段):
a busy cat http://picsearch.ru/share/image-BCE8_4E168F3B.jpg
我有映射:
实体
<class name="LogicalModel.Entity" table="`Entity`" lazy="true">
<id name="Id" ..> ... </id>
<bag name="Attributes" lazy="true" cascade="all-delete-orphan" fetch="select" batch-size="1" access="property" inverse="true">
<key column="`Entity`" />
<one-to-many class="LogicalModel.Attribute" />
</bag>
<bag name="Keys" lazy="true" cascade="all-delete-orphan" fetch="select" batch-size="1" access="property" inverse="true">
<key column="`Entity`" />
<one-to-many class="LogicalModel.Key" />
</bag>
</class>
属性
<class name="LogicalModel.Attribute" table="`Attribute`" lazy="true">
<id name="Id" ..> ... </id>
<many-to-one name="Type" class="LogicalModel.Entity" column="`Type`" cascade="save-update" fetch="select" not-null="true" foreign-key="fk_TypeAttribute" />
<many-to-one name="Entity" class="LogicalModel.Entity" column="`Entity`" cascade="none" fetch="select" not-null="true" foreign-key="fk_EntityAttributes" />
</class>
关键
<class name="LogicalModel.Key" table="`Key`" lazy="true">
<id name="Id" ..> ... </id>
<bag name="KeyAttributes" lazy="true" cascade="all-delete-orphan" fetch="select" access="property" inverse="true">
<key column="`Key`" />
<one-to-many class="LogicalModel.KeyAttribute" />
</bag>
<many-to-one name="Entity" class="LogicalModel.Entity" column="`Entity`" cascade="none" fetch="select" not-null="true" foreign-key="fk_EntityKeys" />
</class>
KeyAttribute:
<class name="LogicalModel.KeyAttribute" table="`KeyAttribute`" lazy="false">
<id name="Id" ..> ... </id>
<many-to-one name="Attribute" class="LogicalModel.Attribute" column="`Attribute`" cascade="save-update" fetch="select" not-null="true" foreign-key="fk_AttributeKeyAttribute" />
<many-to-one name="Key" class="LogicalModel.Key" column="`Key`" cascade="none" fetch="select" not-null="true" foreign-key="fk_KeyKeyAttributes" />
</class>
现在请看一下...... 如您所见,我们已经单向主关联 KeyAttribute - Attribute ,所以它只是多对一的,我根本不需要反向关联。
现在的问题是我正在尝试删除整个图形 - 删除实体对象(注意:实体实际上根本没有加载,它只是代理集,这就是为什么NHibernate会额外添加SELECT查询以在删除之前检查引用) 像这样
Session.Delete(Entity); // here PropertyValueException:
// not-null property references a null or transient value: LogicalModel.KeyAttribute.Attribute
Session.Flush(); // Actually I use transactions in my code, but don't mind
SQL事件探查器:
exec sp_executesql N'SELECT entities0_.[Id] as Id1_1_, entities0_.[Id] as Id1_45_0_,
FROM [Entity] entities0_ WHERE entities0_.[LogicalModel]=@p0',N'@p0 uniqueidentifier',@p0='DC8F8460-9C41-438A-8334-97D0A94E2528'
exec sp_executesql N'SELECT attributes0_.[Entity] as Entity12_1_, attributes0_.[Id] as Id1_1_, attributes0_.[Id] as Id1_16_0_, attributes0_.[Type] as Type11_16_0_, attributes0_.[Entity] as Entity12_16_0_
FROM [Attribute] attributes0_ WHERE attributes0_.[Entity]=@p0',N'@p0 uniqueidentifier',@p0='63E4D568-EAB2-4DF2-8FED-014C8CB2DE22'
exec sp_executesql N'SELECT keys0_.[Entity] as Entity4_1_, keys0_.[Id] as Id1_1_, keys0_.[Id] as Id1_43_0_, keys0_.[Entity] as Entity4_43_0_
FROM [Key] keys0_ WHERE keys0_.[Entity]=@p0',N'@p0 uniqueidentifier',@p0='63E4D568-EAB2-4DF2-8FED-014C8CB2DE22'
exec sp_executesql N'SELECT keyattribu0_.[Key] as Key4_1_, keyattribu0_.[Id] as Id1_1_, keyattribu0_.[Id] as Id1_0_0_, keyattribu0_.[Attribute] as Attribute3_0_0_, keyattribu0_.[Key] as Key4_0_0_
FROM [KeyAttribute] keyattribu0_ WHERE keyattribu0_.[Key]=@p0',N'@p0 uniqueidentifier',@p0='103D8FB3-0B17-4F51-8AEF-9623616AE282'
所以我们可以看到:
not-null属性引用null或transient值:LogicalModel.KeyAttribute.Attribute 发生在NH检查字段属性(数据库中的非空约束,没关系),类 KeyAttribute 之后(参见profiler日志)。
这很有趣,因为NH必须删除属性和KeyAttributes两者,NH读取KeyAttribute类中属性字段的信息, FOUND 它在DB中, NOT FOUND 它在 NH会话(!!!)(因为之前加载了属性),只是抛出这个愚蠢的错误。
我已经尝试过做的事情: 1. make not-null =“false”。在这种情况下,NH进行额外更新 - 尝试设置Attribute = NULL - 导致DB中的约束违规。 2.在KeyAttribute-Attribute的多对一关联上设置lazy =“false”,lazy =“no-proxy” - 没有;
现在我不喜欢拦截器的想法,因为在很多情况下我都有相同的情况,我需要通用解决方案
拜托,伙计们,有什么建议吗?
答案 0 :(得分:1)
在我看来,这可能是由于你对模型的所有实体的延迟负载造成的。 删除实体时,它加载和删除引用的属性列表,加载引用的键列表,加载引用的KeyAttribute列表(具有删除键)然后它属于非null属性引用null或transient值,因为引用的Attribute已被删除之前在会议中。
您可以通过删除映射文件中的所有延迟加载来检查它。
快速解决方案可能是保持延迟加载,但在删除时强制完全加载模型(使用hibernate initialize()),例如在Entity工厂中的Delete(Entity)静态方法中。
答案 1 :(得分:1)
您是否尝试在
中设置on-delete =“cascade”<class name="LogicalModel.Key" table="`Key`" lazy="true">
<id name="Id" ..> ... </id>
<bag name="KeyAttributes" lazy="true" cascade="all-delete-orphan" fetch="select" access="property" inverse="true">
<key column="`Key`" on-delete="cascade" />
<one-to-many class="LogicalModel.KeyAttribute" />
</bag>
<many-to-one name="Entity" class="LogicalModel.Entity" column="`Entity`" cascade="none" fetch="select" not-null="true" foreign-key="fk_EntityKeys" />
因为在配置文件中,您将看到nh尝试将某些内容更新为null,这是一个不可为空的
答案 2 :(得分:0)
NH有时需要将引用设置为null。通常这是为了避免存在循环引用的模型中的问题。但是,找到避免它的方法并不总是足够聪明,即使它是一个。
因此,可能需要在某些外键字段中允许空值,当然不仅在映射文件中,也在数据库中。它实际上应解决问题。
或者,您也可以使用HQL按表删除数据表。这在你没有继承的所有情况下都可以正常工作,如果你知道所有实体和删除它们的顺序:
object entityId;
// gets keys to delete
List<object> keyIds = Session
.CreateQuery("select id from Key where Entity = :entity")
.SetEntity("entity", Entity)
.List<object>();
// delete KeyAttribute which reference the key
Session.CreateQuery("delete KeyAttribute where Key.id in (:keyIds)")
.SetParameterList("keyIds", keyIds)
.ExecuteUpdate();
// delete the keys
Session.CreateQuery("delete Key where id in (:keyIds)")
.SetParameterList("keyIds", keyIds)
.ExecuteUpdate();
// get attributes to delete
List<object> attributeIds = Session
.CreateQuery("select id from Attribute where Entity = :entity")
.SetEntity("entity", Entity)
.List<object>();
// delete KeyAttributes which reference the attributes
Session.CreateQuery("delete KeyAttribute where Attribute.id in (:attributeIds)")
.SetParameterList("attributeIds", attributeIds )
.ExecuteUpdate();
// delete the attributes
Session.CreateQuery("delete Attribute where id in (:attributeIds)")
.SetParameterList("attributeIds", attributeIds )
.ExecuteUpdate();
Session.CreateQuery("delete Entity where id = :entityId")
.SetParameter("entityId", Entity.Id)
.ExecuteUpdate();
注意: