实体框架自我引用层次多对多

时间:2010-03-02 23:26:31

标签: entity-framework many-to-many hierarchical-data self-reference

好的,这个问题已经解决了。

从概念上讲,我有一个可以拥有许多子资源和许多父资源的资源实体。 Resource表有两个字段,ID和Name,ID是主键。

为了完成多对多的关系,我创建了一个ResourceHierarchy表,它有两个字段(Parent_ID,Child_ID)和两个外键,每个字段引用Resource表(ID)的主键,ResourceHierarchy表有一个复合词主键(Parent_ID,Child_ID)

现在我们已经知道每个资源可以作为父资源或子资源充当其他资源,但从逻辑上讲,并非所有资源都会拥有父资源,但除了这一点之外。举个例子,假设我的资源表中有以下资源。

ID    Name
10000 Little House
10001 Font Door
10002 Roof
10003 Roof Tile
10004 Tile Monster

在ResourceHierarchy表中,我们有以下关系。

Parent_ID Child_ID
10000     10001
10000     10002
10002     10003
10004     10003

然后实体框架生成实体,到目前为止一直很好......

如果要检查edmx文件中生成的代码,您会看到ResourceHierarchy表被视为关系,而ResourceHierarchy表无法通过代码访问,因为它不被视为实体。

如果这就是我想要的,那么它将完美无缺。

但是,当我想将数量列添加到资源实体层次结构时,问题就开始了。例如,小房子只有一个前门和一个屋顶,但屋顶和瓷砖怪物资源可以有很多屋顶瓦片。

因此,如果我们将一个Quantity列添加到Resource表中,那么我们得到以下内容。

ID    Name            Quantity
10000 Little House 1
10001 Font Door  1
10002 Roof   1
10003 Roof Tile  5
10004 Tile Monster 1

这就产生了屋顶和瓷砖怪物必须共享5个屋顶瓦片的问题。所以我自然会尝试将quantity列添加到ResourceHierarchy表中,但是只要我这样做并刷新生成的代码,现在将ResourceHierarchy表视为实体而不是之前的关系。现在,为了回到资源表,我必须经历这个非概念性的“实体/关系”,这不是很直接。这就像我的概念模型中有一个Entity,它只用于遍历资源实体,我甚至不确定Resource.Children.Add(r)是否会在db的ResourceHierarchy表中创建新行。这就像我将从一个我只用作关系的实体中挑选出属性,即数量。

理想情况下,ResourceHierarchy表的Quantity列看起来像这样。

Parent_ID Child_ID Quantity
10000     10001  1
10000     10002  1
10002     10003  8
10004  10003  13

并且资源实体仍然具有子项,父项导航属性,并以某种方式访问​​“数量”列作为资源实体的属性。

我尝试合并生成的代码,从拥有数量列而不是数量列但抛出异常,我将其解释为ResourceHierarchy表可以是关系或实体,但不是两者。

请帮助!

edmx在db中的ResourceHierarchy表中添加和排除quantity列时发生了巨大变化。

以下是一个示例比较,唯一的区别是Resource是ResourceType,ResourceHierarchy是ResourceTypeHierarchy。

SSDL存储模型除了ResourceTypeHierarchy EntityType中的一个额外属性外没有任何更改,所以我不会在下面包含它。

没有关于资源等级的数量列

RESOURCETYPEHIERARCHY是一种关系

<!-- CSDL content -->
        <edmx:ConceptualModels>
          <Schema Namespace="MyModel" Alias="Self" xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" xmlns="http://schemas.microsoft.com/ado/2008/09/edm">
            <EntityContainer Name="MyEntities">
              <EntitySet Name="ResourceTypes" EntityType="MyModel.ResourceType" />
              <AssociationSet Name="ResourceTypeHierarchy" Association="MyModel.ResourceTypeHierarchy">
                <End Role="ResourceType" EntitySet="ResourceTypes" />
                <End Role="ResourceType1" EntitySet="ResourceTypes" /></AssociationSet></EntityContainer>
            <EntityType Name="ResourceType">
              <Key>
                <PropertyRef Name="ID" /></Key>
              <Property Type="Int32" Name="ID" Nullable="false" />
              <Property Type="String" Name="Type" Nullable="false" MaxLength="25" FixedLength="false" Unicode="false" />
              <NavigationProperty Name="Parents" Relationship="MyModel.ResourceTypeHierarchy" FromRole="ResourceType" ToRole="ResourceType1" />
              <NavigationProperty Name="Children" Relationship="MyModel.ResourceTypeHierarchy" FromRole="ResourceType1" ToRole="ResourceType" /></EntityType>
            <Association Name="ResourceTypeHierarchy">
              <End Type="MyModel.ResourceType" Role="ResourceType" Multiplicity="*" />
              <End Type="MyModel.ResourceType" Role="ResourceType1" Multiplicity="*" /></Association></Schema>
        </edmx:ConceptualModels>


<!-- C-S mapping content -->
        <edmx:Mappings>
          <Mapping Space="C-S" xmlns="http://schemas.microsoft.com/ado/2008/09/mapping/cs">
            <EntityContainerMapping StorageEntityContainer="MyModelStoreContainer" CdmEntityContainer="MyEntities">
              <EntitySetMapping Name="ResourceTypes">

                <EntityTypeMapping TypeName="IsTypeOf(MyModel.ResourceType)">
                  <MappingFragment StoreEntitySet="ResourceType">
                    <ScalarProperty Name="ID" ColumnName="ID" />
                    <ScalarProperty Name="Type" ColumnName="Type" /></MappingFragment></EntityTypeMapping></EntitySetMapping>
              <AssociationSetMapping Name="ResourceTypeHierarchy" TypeName="MyModel.ResourceTypeHierarchy" StoreEntitySet="ResourceTypeHierarchy">
                <EndProperty Name="ResourceType1">
                  <ScalarProperty Name="ID" ColumnName="Parent_ID" /></EndProperty>
                <EndProperty Name="ResourceType">
                  <ScalarProperty Name="ID" ColumnName="Child_ID" /></EndProperty></AssociationSetMapping></EntityContainerMapping>
          </Mapping>
        </edmx:Mappings>

在资源层面上有数量列

RESOURCETYPEHIERARCHY现在是一个实体

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               

<!-- C-S mapping content -->
<edmx:Mappings>
  <Mapping Space="C-S" xmlns="http://schemas.microsoft.com/ado/2008/09/mapping/cs">
    <EntityContainerMapping StorageEntityContainer="MyModelStoreContainer" CdmEntityContainer="MyEntities">
      <EntitySetMapping Name="ResourceTypes">

        <EntityTypeMapping TypeName="IsTypeOf(MyModel.ResourceType)">
          <MappingFragment StoreEntitySet="ResourceType">
            <ScalarProperty Name="ID" ColumnName="ID" />
            <ScalarProperty Name="Type" ColumnName="Type" /></MappingFragment></EntityTypeMapping></EntitySetMapping>
      <EntitySetMapping Name="ResourceTypeHierarchies">

        <EntityTypeMapping TypeName="IsTypeOf(MyModel.ResourceTypeHierarchy)">
          <MappingFragment StoreEntitySet="ResourceTypeHierarchy">
            <ScalarProperty Name="Child_ID" ColumnName="Child_ID" />
            <ScalarProperty Name="Parent_ID" ColumnName="Parent_ID" />
            <ScalarProperty Name="Quantity" ColumnName="Quantity" /></MappingFragment></EntityTypeMapping></EntitySetMapping>
      <AssociationSetMapping Name="FK_Child" TypeName="MyModel.FK_Child" StoreEntitySet="ResourceTypeHierarchy">
        <EndProperty Name="ResourceTypeHierarchy">
          <ScalarProperty Name="Child_ID" ColumnName="Child_ID" />
          <ScalarProperty Name="Parent_ID" ColumnName="Parent_ID" /></EndProperty>
        <EndProperty Name="ResourceType">
          <ScalarProperty Name="ID" ColumnName="Child_ID" /></EndProperty></AssociationSetMapping>
      <AssociationSetMapping Name="FK_Parent" TypeName="MyModel.FK_Parent" StoreEntitySet="ResourceTypeHierarchy">
        <EndProperty Name="ResourceTypeHierarchy">
          <ScalarProperty Name="Child_ID" ColumnName="Child_ID" />
          <ScalarProperty Name="Parent_ID" ColumnName="Parent_ID" /></EndProperty>
        <EndProperty Name="ResourceType">
          <ScalarProperty Name="ID" ColumnName="Parent_ID" /></EndProperty></AssociationSetMapping></EntityContainerMapping>
  </Mapping>
</edmx:Mappings>

1 个答案:

答案 0 :(得分:1)

我相信这是有道理的。我的意思是,如果你把一个属性放在一个建立两个实体之间关系的表上,那么该表必须(至少从数据表示理论)表示为一个合适的实体。如果仔细考虑一下,你会理解为什么。您提到的数量是关系的属性,而不是任何相关实体的属性。因此,必须将表视为实体而不是关系。

现在关于如何克服这个问题,我想到的一件事(虽然我不确定这是否会完全解决你的问题)是按照你原先的想法处理关系(没有数量)并且有另一张表(将映射到您模型中的实体),用于存储特定关系的数量。我认为这个表甚至可以对你的db到原始关系表有一个外键约束,虽然这个外键不能映射到模型上的关系(因为你没有端点的实体),但这仍然是允许您在存储上保持数据完整性。

希望这有帮助, 维克托•