具有相同 ID 键字段的多对多

Posted

技术标签:

【中文标题】具有相同 ID 键字段的多对多【英文标题】:Many-to-many with Same Id Key fields 【发布时间】:2019-03-14 20:59:33 【问题描述】:

如何在 nHibernate 中将两个表连接为多对一和一对多。它们都具有与键列相同的“PLAN_ID”。我的数据库结构预先存在。

下面是我正在使用的映射和我得到的错误:

表:PLANN一个

PLAN_ID  <-- PRIMARY KEY
START_DATE
CHECK_CHAR
...

表格:PLANN_DOCUMENT对许多

PLAN_ID <-- PRIMARY KEY
DOC_ID <-- ID to a DOCUMENT table
DOC_NAME
DOC_TYPE

计划类:

public virtual... PlanId, StartDate, CheckChar, PlanStatus,
public virtual ISet<DocsysHoldingDoc> DocsysHoldingDocs  get; set; 
public virtual DocsysHoldingDoc DocsysHoldingDoc  get; set; 

PlannDocument 类:

public virtual...PlanId, DocId, DocName, DocType
public virtual Plann PlannItem  get; set; 

规划 HBM XML

<class name="Plann" abstract="true" table="PLANN">
    <id name="PlanId" column="PLAN_ID"
        <generator class="assigned"/>
    </id>
    <property name="StartDate" column="START_DATE" /> 
    <property name="CHECK_CHAR" column="CHECK_CHAR" /> 
    ...

    <set name="PlannDocument" table="PLANN_DOCUMNET">
        <key column="PLAN_ID"></key> //<<KEY IN JOINING TABLE BUT ALSO ID IN THIS TABLE
        <one-to-many class="DocsysHoldingDoc"/>
     </set>
</class>

PlannDocument HBM XML

<class name="PlannDocument" abstract="true" table="PLANN_DOCUMNET">
    <id name="PlanId" column="PLAN_ID"  type = "int">
        <generator class="assigned"/>
    </id>
    <property name="DocId" column="DOC_ID" />
    <property name="DocName" column="DOC_NAME" />
    <property name="DocType" column="DOC_TYPE" />

    <many-to-one name="Plann" column="PLAN_ID"></many-to-one>

</class>

错误: NHibernate.MappingException: '无法为类 .PlannDocument 构建插入语句:添加类的 Id 时发生故障'

ArgumentException: “PLAN_ID”列已添加到此 SQL 构建器中 参数名称:columnName

我在这里做错了吗?

【问题讨论】:

【参考方案1】:

如果identifier 和您想要的many-to-one 关联具有相同的列 - 这并不是真正的many-to-one 关联。共享相同的identifier 意味着它是one-to-one 关联。只需使用它而不是 PlannDocument.hbm.xml 中的 many-to-one 映射,它应该可以工作:

<one-to-one name="Plann" constrained="true" />

如果您的PlannDocument.Plann 可以为空,请改用constrained="false"。但请注意,这将花费您额外的查询来检查 Plann 是否真的存在。

【讨论】:

好点,但问题清楚地表明一个PLANN 可能有很多PLANN_DOCUMNETs。【参考方案2】:

根据您的 cmets(在已删除的答案下),两个表中的主键列的名称相同 - 即 PLAN_ID。您想基于多对一关系连接这两个表。

这里的问题是相同的列名(来自两个不同的表)在映射中被添加了两次。

这就是错误的原因:

ERROR: NHibernate.MappingException: '无法为类 构建插入语句。PlannDocument:添加类的 Id 时发生故障'

ArgumentException:列 'PLAN_ID' 已添加到此 SQL 构建器中参数名称:columnName

在 PlannDocument HBM 中,列名 PLAN_ID 在创建 id 时首先使用,如下所示:

<id name="PlanId" column="PLAN_ID"  type = "int">

然后,在创建many-to-one 关系时再次如下:

<many-to-one name="Plann" column="PLAN_ID"></many-to-one>

这导致列名冲突。

我能想到的解决方案是将列名更改为与其他表不同的名称。此外,相应地修改类和映射。

我知道这不可能是每次和所有情况下的解决方案。

【讨论】:

以上是关于具有相同 ID 键字段的多对多的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 4:具有额外关系的多对多

Django,使用最低参数的多对多字段元素的ID注释字段

SQLite中的多对多链接表外键建模

Prisma 删除与复合键的多对多关系

Doctrine 2 和带有额外字段的多对多链接表

如何过滤和访问 Django QuerySet 中的多对多字段?