实体框架自引用分层多对多
Posted
技术标签:
【中文标题】实体框架自引用分层多对多【英文标题】:Entity Framework Self Referencing Hierarchical Many To Many 【发布时间】:2010-03-02 23:26:30 【问题描述】:好的,这个问题解决了。
从概念上讲,我有一个资源实体,它可以有许多子资源和许多父资源。 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
然后Entity Framework生成Entity,到目前为止一切顺利……
如果您要检查 edmx 文件中生成的代码,您会看到 ResourceHierarchy 表被视为关系,并且 ResourceHierarchy 表无法通过代码访问,因为它没有被视为实体。
如果这就是我想要的,那么它会很完美。
但是,当我想将数量列添加到资源实体层次结构时,问题就开始了。例如,小房子只有一个前门和一个屋顶,但屋顶和瓷砖怪物资源可以有许多屋顶瓦片。
因此,如果我们在 Resource 表中添加一个 Quantity 列,那么我们会得到以下结果。
ID Name Quantity
10000 Little House 1
10001 Font Door 1
10002 Roof 1
10003 Roof Tile 5
10004 Tile Monster 1
这就产生了屋顶和瓦片怪物必须共享 5 个屋顶瓦片的问题。所以很自然地,我会尝试将数量列添加到 ResourceHierarchy 表中,但是一旦我这样做并刷新生成的代码,现在将 ResourceHierarchy 表视为一个实体,而不是以前的关系。现在为了回到资源表,我必须通过这个非概念性的“实体/关系”,这不是很直接。就像我的概念模型中有一个实体,它只用于遍历资源实体,我什至不确定 Resource.Children.Add(r) 是否会在数据库的 ResourceHierarchy 表中创建新行.就像我会从我仅用作关系的实体中挑选属性,即数量。
理想情况下,ResourceHierarchy 表的 Quantity 列应如下所示。
Parent_ID Child_ID Quantity
10000 10001 1
10000 10002 1
10002 10003 8
10004 10003 13
并且资源实体仍将具有子项、父项导航属性,并且以某种方式访问数量列作为资源实体的属性。
我尝试将生成的代码从有数量列和没有数量列合并,但引发异常,我将其解释为 ResourceHierarchy 表可以是关系或实体,但不能两者兼而有之。
p>请帮忙!
随着 db 中 ResourceHierarchy 表中数量列的添加和排除,edmx 发生了巨大变化。
这里是一个示例比较,唯一的区别是 Resource 是 ResourceType 而 ResourceHierarchy 是 ResourceTypeHierarchy。
SSDL 存储模型除了 ResourceTypeHierarchy EntityType 中的一个额外属性外没有任何变化,所以我不会在下面包含它。
在资源类型层次结构中没有数量列
资源类型层次结构是一种关系
<!-- 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】:我相信这是按预期工作的。我的意思是,如果您将一个属性放在建立两个实体之间的关系的表上,那么该表必须(至少从数据表示理论)被表示为一个适当的实体。如果你仔细考虑一下,你就会明白为什么。您提到的数量是关系的属性,而不是任何相关实体的属性。因此,该表必须被视为实体而不是关系。
现在关于如何克服这个问题,我想到的一件事(尽管我不确定这是否会完全解决您的问题)是按照您最初的想法处理关系(没有数量)并有另一个表(将映射到模型中的实体)存储特定关系的数量。我认为这个表甚至可以对你的数据库有一个外键约束到原始关系表,虽然这个外键不能映射到你的模型上的关系(因为你没有端点的实体),但这仍然允许您在存储中保持数据完整性。
希望这会有所帮助, 维托
【讨论】:
以上是关于实体框架自引用分层多对多的主要内容,如果未能解决你的问题,请参考以下文章