【问题标题】:Why can't I reference child entities with part of the parent entities composite key为什么我不能使用部分父实体复合键引用子实体
【发布时间】:2011-01-20 01:57:10
【问题描述】:

我试图用部分父复合键而不是全部引用一些子实体,为什么不能?当我使用以下映射而不是注释的映射时,就会发生这种情况。

我收到以下错误

表中的外键 VolatileEventContent 必须相同 引用的列数 表中的主键 位置搜索查看

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="JeanieMaster.Domain.Entities" assembly="JeanieMaster.Domain">
  <class name="LocationSearchView" table="LocationSearchView">

    <composite-id>
      <key-property name="LocationId" type="Int32"></key-property>
      <key-property name="ContentProviderId" type="Int32"></key-property>
      <key-property name="CategoryId" type="Int32"></key-property>
    </composite-id>

    <property name="CompanyName" type="String" not-null="true" update="false" insert="false"/>
    <property name="Description" type="String" not-null="true" update="false" insert="false"/>
    <property name="CategoryId" type="Int32" not-null="true" update="false" insert="false"/>
    <property name="ContentProviderId" type="Int32" not-null="true" update="false" insert="false"/>
    <property name="LocationId" type="Int32" not-null="true" update="false" insert="false"/>
    <property name="Latitude" type="Double"  update="false" insert="false" />
    <property name="Longitude" type="Double"  update="false" insert="false" />

    <bag name="Events" table="VolatileEventContent" where="DeactivatedOn IS NULL" order-by="StartDate DESC" lazy="false" cascade="none">
      <key>
        <column name="LocationId"></column>
        <column name="ContentProviderId"></column>
        <!--<column name="LocationId"></column>
        <column name="ContentProviderId"></column>
        <column name="CategoryId"></column>-->
      </key>
      <one-to-many class="Event" column="VolatileEventContentId"></one-to-many>
    </bag>

  </class>
</hibernate-mapping>

和 VolatileEventContent 映射文件

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="JeanieMaster.Domain.Entities" assembly="JeanieMaster.Domain">
  <class name="Event" table="VolatileEventContent" select-before-update="false" optimistic-lock="none">
    <composite-id>
      <key-property name="LocationId" type="Int32"></key-property>
      <key-property name="ContentProviderId" type="Int32"></key-property>
    </composite-id>

    <property name="Description" type="String" not-null="true" update="false" insert="false"/>

    <property name="StartDate" type="DateTime" not-null="true" update="false" insert="false" />
    <property name="EndDate" type="DateTime" not-null="true" update="false" insert="false" />

    <property name="CreatedOn" type="DateTime" not-null="true" update="false" insert="false" />
    <property name="ModifiedOn" type="DateTime" not-null="false" update="false" insert="false" />

    <many-to-one name="Location" class="Location" column="LocationId" />

    <bag name="Artistes" table="EventArtiste" lazy="false" cascade="none">
      <key name="VolatileEventContentId" />
      <many-to-many class="Artiste" column="ArtisteId" ></many-to-many>
    </bag>
  </class>
</hibernate-mapping>

【问题讨论】:

  • 你能把VolatileEventContent的映射也贴出来吗?
  • 添加了额外的映射

标签: c# nhibernate hibernate composite-id


【解决方案1】:

错误是正确的。我猜您正在使用SchemaExport 根据 NHibernate 映射生成表,因为您收到的错误听起来像是在创建表和外键期间发生的。 SchemaExport 将生成类似于以下的表格(请注意散布在代码中的解释):

CREATE TABLE LocationSearchView (
    LocationId int NOT NULL,
    ContentProviderId int NOT NULL,
    CategoryId int NOT NULL,

    /* ...other columns... */

    /* Note: Generated from LocationSearchView's "composite-id" element.  */
    PRIMARY KEY (LocationId, ContentProviderId, CategoryId)
);

/* Note: Table for the "Event" class. */
CREATE TABLE VolatileEventContent (
    LocationId int NOT NULL,
    ContentProviderId int NOT NULL,

    /* ...other columns... */

    /* Note: Generated from Event's "composite-id" element. */
    PRIMARY KEY (LocationId, ContentProviderId),
    /* Note: Generated from the "key" element of LocationSearchView's Events bag. */
    FOREIGN KEY (LocationId, ContentProviderId) REFERENCES LocationSearchView (LocationId, ContentProviderId)
);

...因此出现错误。外键必须指向完整的主键或唯一键——而不仅仅是主键的一部分。整个键是 3 列,而不是 2。为什么 NHibernate 会使用这些列作为外键?因为LocationSearchViewEvents 包的&lt;key&gt; 元素。 &lt;key&gt; 指定 child 中的哪些列指向 parent

让我们考虑一下当您(或 NHibernate)尝试从这些表中进行选择时会发生什么。假设以下数据:

表位置搜索查看 LocationId ContentProviderId CategoryId ========== ============================ 1 3 5 1 3 6 1 4 5 1 4 6 2 3 5 2 3 6 2 4 5 2 4 6 表 VolatileEventContent LocationId ContentProviderId ========== ================== 1 3 1 4 2 3 2 4

“一个”LocationSearchView 不可能有“多个”Events。相反,它应该是相反的。鉴于这些表,从EventLocationSearchView 之间确实存在一对多关系。

我不知道此问题的正确解决方案是什么,因为我不知道您要完成什么,但希望这有助于阐明问题的确切含义。

【讨论】:

  • 感谢丹尼尔的回复,hbm 文件代表我的表,我没有使用 SchemaExport(无论如何)这是事件与 LocationSearchView 的关系我有问题
  • SchemaExport 是一个根据您的 NHibernate 映射生成表的工具。我假设您正在使用它,因为“外键......必须具有相同数量的列......”听起来像是在创建表和外键期间会发生的错误。你能提供这个错误的堆栈跟踪吗?我对您的表结构的猜测不正确吗?我将更新我的答案以解释为什么我认为您的表格看起来像那样。
【解决方案2】:

我从未使用过 nhibernate,但我猜映射与 hibernate 非常相似。

如果您不希望您的一对多(LocationSearchView 到多个 VolatileEventContent)关联使用 LocationSearchView id,则需要在包的关键元素上定义属性“property-ref”,该属性将定义要使用的属性:

<bag name="Events" table="VolatileEventContent" ...>
  <key property-ref="partialId">
    <column name="LocationId"></column>
    <column name="ContentProviderId"></column>
  </key>
  <one-to-many class="Event" column="VolatileEventContentId"></one-to-many>
</bag>

(列属性在一对多标签上有效?)

现在您需要定义一个具有该名称的属性,类似这样:

<properties name="partialId" insert="false" update="false">
  <property name="LocationId" type="Int32" update="false" insert="false"/>
  <property name="ContentProviderId" type="Int32" update="false" insert="false"/>
</properties>

您已经定义了 LocationId 和 ContentProviderId。只需将这两个属性移动到 properties 元素中即可。

【讨论】:

  • 不幸的是 property-ref 不是一个公认的属性:(
【解决方案3】:

首先,“LocationSearchView”的映射有错误 您将 CategoryId 列定义为属性和 Composite-id 的一部分。这是错误的,但不幸的是,它在构建映射时没有被捕获,并且通常在查询对象时暴露出来。检查IndexOutOfRangeException Deep in the bowels of NHibernate

这可能会混淆映射解析器。我说的是令人困惑的,因为在您的映射中,您都依赖反射和约定,这意味着更规范的编程方法:

  1. 您没有明确定义many-to-onebag 元素的class 属性,而是希望NHibernate 从类定义本身检测类类型。如果您有任何机会在LocationSearchView 类中设置了以下IList&lt;LocationSearchView&gt; Events {get;set;},nhibernate 会期望为定义的bag 找到LocationSearchView 类,因此需要 3 列来映射集合
  2. 列名称具有相同的属性名称,这使开发更容易(实际上它只会使创建映射变得更容易,无论如何您只需要创建一次或两次)但如果出现错误或更改,则更难检测到什么出错了。

所以,让您的映射更丰富,并删除我在CategoryId 中提到的错误,同时在您的帖子中包含这些类!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-12
    • 1970-01-01
    • 2021-06-01
    • 1970-01-01
    • 2019-04-13
    相关资源
    最近更新 更多