【问题标题】:NHibernate - When adding an object to a many-to-many collection, existing objects are removed and reinsertedNHibernate - 将对象添加到多对多集合时,现有对象将被删除并重新插入
【发布时间】:2010-12-01 12:45:47
【问题描述】:

我正在使用多对多映射表,将字段映射到对象。

相关数据库结构...

对象:表
(pk) 对象ID
[其他无关紧要]

字段:表格
(pk) 字段ID
[其余的无关紧要]

ObjectFields:表格
(pk) fieldObjectid (fk) fkObjectId -> 对象 (fk) fkFieldId -> 字段

我的映射如下所示:

<bag name="Fields" table="ObjectFields" lazy="true" cascade="all">
  <key column="fkObjectId"/>
  <many-to-many class="Field" column="fkFieldId" />
</bag>

现在,所有收集操作都按您的预期工作 - 检索、添加和删除。但是,发生了一件非常奇怪的事情。如果我将一个对象添加到“字段”集合中,NHibernate 会删除已经存在的内容并重新插入它。

这是我的 log4net 转储: DEBUG NHibernate.SQL [(null)] - 选择 this_.objectId 作为 objectId6_0_, this_.Name 作为 Name6_0_, this_.Description 作为 Descript3_6_0_, this_.RootElement 作为 RootElem4_6_0_, this_.ChildElement 作为 ChildEle5_6_0_, this_.ImageUrl 作为 ImageUrl6_0_, this_.hasChildren as hasChild7_6_0_, this_.CreateStamp as CreateSt8_6_0_ FROM Objects this_ WHERE this_.objectId = @p0;@p0 = 5 [类型:Int32 (0)]
调试 NHibernate.SQL [(null)] - 选择 fields0_.fkObjectId 作为 fkObjectId1_,fields0_.fkFieldId 作为 fkFieldId1_,inventoryf1_.fieldId 作为 fieldId4_0_,inventoryf1_.fieldName 作为 fieldName4_0_,inventoryf1_.fieldType 作为 fieldType4_0_,inventoryf1_.Required 作为Required4_0_ FROM ObjectFields fields0_ left外连接字段inventoryf1_ on fields0_.fkFieldId=inventoryf1_.fieldId WHERE fields0_.fkObjectId=@p0;@p0 = 5 [类型:Int32 (0)]
DEBUG NHibernate.SQL [(null)] - 选择 this_.fieldId 作为 fieldId4_0_, this_.fieldName 作为 fieldName4_0_, this_.fieldType 作为 fieldType4_0_, this_.Required 作为Required4_0_ FROM Fields this_ WHERE this_.fieldId = @p0;@p0 = 2 [类型:Int32 (0)]
调试 NHibernate.SQL [(null)] - 从 ObjectFields 中删除 fkObjectId = @p0;@p0 = 5 [类型:Int32 (0)]
DEBUG NHibernate.SQL [(null)] - INSERT INTO ObjectFields (fkObjectId, fkFieldId) VALUES (@p0, @p1);@p0 = 5 [Type: Int32 (0)], @p1 = 1 [Type: Int32 (0 )]
DEBUG NHibernate.SQL [(null)] - INSERT INTO ObjectFields (fkObjectId, fkFieldId) VALUES (@p0, @p1);@p0 = 5 [Type: Int32 (0)], @p1 = 2 [Type: Int32 (0 )]

如您所见,它发出删除语句,然后重新插入。

任何想法如何防止这种情况?

【问题讨论】:

    标签: .net nhibernate


    【解决方案1】:

    简而言之,包的行为就是这样,你应该使用另一种类型的集合。这里你有一个来自 NHibernate 文档的很好的解释,但我建议你阅读整章 (17.5. Understanding Collection performance

    所有索引集合(映射、列表、数组)都有一个由索引列组成的主键。在这种情况下,集合更新通常非常有效 - 主键可能会被有效地索引,并且当 NHibernate 尝试更新或删除特定行时,它可能会被有效地定位。

    集合有一个由键和元素列组成的主键。对于某些类型的集合元素,特别是复合元素或大文本或二进制字段,这可能效率较低;数据库可能无法有效地索引复杂的主键。另一方面,对于一对多或多对多关联,特别是在合成标识符的情况下,它可能同样有效。 (旁注:如果您希望 SchemaExport 实际为您创建集合的主键,则必须将所有列声明为 not-null="true"。)

    idbag 映射定义了一个代理键,因此更新它们总是非常有效。事实上,它们是最好的情况。

    包是最坏的情况。由于包允许重复的元素值并且没有索引列,因此可以不定义主键。 NHibernate 无法区分重复的行。 NHibernate 通过完全删除(在单个 DELETE 中)并在集合发生更改时重新创建集合来解决此问题。这可能效率很低。

    【讨论】:

    • 感谢克劳迪奥 - 有道理。那么问题是,我的映射表有一个主键;我该如何关联?它与我的课程完全无关,实际上“业务逻辑”不需要知道它。 Hibernate 可以自动处理吗?
    • 另外,在更改为集合后,我得到一个 TypeInitializationException: {"Foreign key (FK1427E785C0DFD3B9:FieldInstance [fieldObjectId])) 必须具有与引用的主键相同的列数 (FieldInstance [fkObjectInstanceId, fieldObjectId])"}
    【解决方案2】:

    我发现在我的情况下,身份证袋更适合我,但克劳迪奥的另一个回答很好。

    【讨论】:

      猜你喜欢
      • 2015-03-08
      • 1970-01-01
      • 2018-10-05
      • 2021-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多