为了账号安全,请及时绑定邮箱和手机立即绑定

更新行李例外情况

更新行李例外情况

C#
慕仙森 2023-08-20 15:50:28
我有这样的数据库表:[表记录]RecordId    MyColumn1   MyColumn2  ----------------------------------112         somedata8   somedata7   112         somedata6   somedata1   148         somedata3   somedata5[tbl记录水果]RecordId    FruitTypeId  -------------------------  112         53    112         85    148         16  [表水果类型]FruitTypeId     Text  ----------------------53              Apple  85              Banana  16              Orange  以及对应的NHibernate映射:<?xml version="1.0" encoding="utf-8"?><hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">    <class name="Record, Infrastructure.Interface"           table="tblRecord">        <id name="Id" type="Int32" unsaved-value="null">            <column name="RecordId" length="4" sql-type="int" not-null="true" unique="true" index="PK_tblRecord" />            <generator class="native" />        </id>        ...        <bag name="Fruits" table="tblRecordFruit" inverse="false" lazy="true" cascade="save-update">            <key>                <column name="RecordId" length="4" sql-type="int" not-null="true" />            </key>            <many-to-many                class="FruitType, Infrastructure.Interface">                <column name="FruitTypeId" length="2" sql-type="smallint" not-null="true" />            </many-to-many>        </bag>        ...    </class></hibernate-mapping><?xml version="1.0" encoding="utf-8"?><hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">  <class name="FruitType, Infrastructure.Interface"         table="tblFruitType"         mutable="false"         lazy="false">    <id name="Id" type="Int16" unsaved-value="0">      <column name="FruitTypeID" sql-type="smallint" not-null="true" unique="true" index="PK_Fruit" />      <generator class="native" />    </id>    <property name="Text" type="String">      <column name="Text" length="255" sql-type="varchar" not-null="true" />    </property>  </class></hibernate-mapping>
查看完整描述

2 回答

?
绝地无双

TA贡献1946条经验 获得超4个赞

如果我理解正确,您正在尝试更新Record与会话断开连接的对象。因此您可以使用Merge会话重新连接。


在这种情况下,为了使Merge您的集合工作,它们需要merge映射中的级联选项。因此,请尝试Fruits使用以下命令更新您的映射: cascade="merge,save-update"或简单地使用以下命令来更新您的映射cascade="all"以涵盖所有情况:


<bag name="Fruits" table="tblRecordFruit" inverse="false" lazy="true" cascade="all">       

PS调用实际上应该与您现有的映射SaveOrUpdate一起正常工作。也许您在更新映射之前已经尝试过,否则请确保异常相同并提供.Fruitscascade="save-update"Fruit


更新 1因此,如前所述,我假设您正在尝试更新分离的实体(从不同会话加载的实体)。请确认并提供详细信息到底是如何发生的?它是否从 UI 上显示的状态进行序列化/反序列化?


在这种情况下,您应该意识到需要在保存对象后序列化状态。因为保存后Fruits集合类型更改为正确处理进一步更新所需的内部 NHibernate 集合。因此,当record.Fruits.Add(obj)调用现有Record对象时,它的类型record.Fruits一定不能List<T>是 NHibernate 类型(据说PersistangGenericType<T>)。


因此,请确保您没有覆盖现有对象的集合属性:


record.Fruits = new List<FruitType>();// WRONG for existing record...


//Instead clear existing record collection:

record.Fruits.Clear(); //Correct

还要在调试器中进行以下检查:


//You somehow obtain record instance that you want to update

var record = DeserializeOrLoadState(recordId);


...//When you update existing record

record.Fruits.Add(fruitType1);// Make sure in debugger that for existing record record.Fruits is NHibernate type PesistentGenericBag<T> and not List<T>


...//When you SaveOrUpdate/Merge existing record

session.Merge(record);// <- make sure in debugger that for existing record.Fruits is NHibernate type PesistentGenericBag<T> and not List<T>


...

SerializeState(record);// serialize state only after session.SaveOrUpdate

更新2


它不是 PersistentGenericBag。这曾经有效。现在从 NHibernate v2 到 v4 的更改是否可能会导致此问题?


我不知道它是如何在 NHibernate v2 中完成的 - 但它肯定可以在您的代码中修复。所以你需要调查为什么它仍然存在List——这表明你做错了什么。一些建议:


1) 如果你的Fruits属性有 setter - 删除它以确保所有操作都是通过IList方法完成的:


public class Record

{

    public virtual IList<FruitType> Fruits {get; } = new List<FruitType>()

}

2)调查这部分Then the user opens that record again and adds another FruitType to it.。你还没说它是如何实现的。这里的UI <-> Entity 映射是如何实现的?当从数据库加载现有实体时,我很确定它不是ListNHibernate 类型。所以你应该调试并找到它更改为 的地方List。


3) 还尝试将级联设置更改为cascade="all-delete-orphan"。我不认为这会改变任何事情——但以防万一。


查看完整回答
反对 回复 2023-08-20
?
白猪掌柜的

TA贡献1893条经验 获得超10个赞

例外情况:


违反主键约束“PK_tblRecordFruit_1”。无法在对象“dbo.tblRecordFruit”中插入重复的键。重复的键值为 (112, 53)。


说违反了主键约束。这意味着您正在尝试复制主键列的值。


查看映射中的以下代码块:


<bag name="Fruits" table="tblRecordFruit" inverse="false" lazy="true" cascade="save-update">

    <key>

        <column name="RecordId" length="4" sql-type="int" not-null="true" />

    </key>

看来这RecordId是你在桌子上的主键tblRecordFruit。如果是这种情况,很明显您无法将问题中提到的示例数据插入到表中:


RecordId    FruitTypeId

-----------------------

  112         53

  112         85

  148         16

该值112不能在列中重复RecordId。如果您的代码尝试执行此操作,很明显您将得到您所说的异常。


您是否正在寻找复合键(在 和RecordId列上FruitTypeId)?


首先,需要注意的是:复合键在 NHibernate 中当然是可映射的,但它比典型的单个身份键要复杂一些。与普通密钥相比,有一些额外的设置工作,查询更加痛苦,并且它们在延迟加载方面往往不太优化。由于这些原因,经验丰富的 NHibernate 用户通常会尽可能避免使用复合键。

......

_


<composite-id>

    <key-many-to-one class="SuperShop.Domain.OrderItemComponent,SuperShop.Domain" name="OrderItemComponent" column="OrderItemProductID" />

    <key-property name="DetailType" column="DetailTypeID" type="SuperShop.Domain.DetailTypes,SuperShop.Domain" />

</composite-id>

<version name="LastModifiedOn"....


查看完整回答
反对 回复 2023-08-20
  • 2 回答
  • 0 关注
  • 129 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信