10

我目前有一个实体框架 4.0 模型和每个类型的表 (TPT),但存在一些性能问题(许多 LOJ 的/CASE 语句),以及两个特定领域区域之间的问题映射(多对 -许多)。

我决定试试TPH。

我有一个名为“位置”的实体,它是抽象的,也是所有其他实体的基础。

然后我有“ Country ”、“ City ”、“ State ”、“ Street ”等,它们都来自 Location。

LocationType ”是判别器

该部分工作正常,但我在尝试为派生类型定义导航属性时遇到问题。

例如,一个“”有一个“国家”,所以我应该能够做到这一点:

var state = _ctx.Locations.OfType<State>().Include("Country").First();
var countryForState = state.Country;

但这需要在“State”派生实体上具有一个名为“Country”的导航属性。我该怎么做呢?当我从数据库生成模型时,我有一个表,所有 FK 都指向同一个表中的记录:

替代文字

(注意:我在数据库中手动创建了这些 FK)。

但是 FK 被放置为“位置”实体上的导航,那么我如何将这些导航属性向下移动到派生实体?我无法复制+粘贴导航,也无法“创建新的导航属性”,因为它不会让我定义开始/结束角色。

我们如何做到这一点?

TPH 也不清楚我们是否可以先做模型,或者我们必须从数据库开始,修复模型然后重新生成数据库。我还没有在互联网上找到一个关于如何定义 TPH 儿童导航的好例子。

注意:我不想做代码优先。我当前的解决方案有 EDMX 和纯 POCO 的 TPT,我希望不影响域模型/存储库(如果可能),并且只更新 EF 模型/数据库。

编辑

仍然没有解决方案-但是我尝试先执行模型,然后执行添加-> 新关联,这实际上允许我向派生实体添加导航。但是当我尝试“从模型生成数据库”时,它仍然尝试为“Location_Street”、“Location_Country”等创建表。这几乎就像 TPH 不能先做模型一样。

编辑

这是我目前的模型:

替代文字

我目前得到的验证错误:

错误 1 ​​错误 3002:从第 359 行开始映射片段时出现问题:表位置键 (Locations.LocationId) 的潜在运行时违规:列 (Locations.LocationId) 在概念方面映射到 EntitySet NeighbourhoodZipCode 的属性 (NeighbourhoodZipCode.Neighbourhood.LocationId)但它们不构成 EntitySet 的关键属性(NeighbourhoodZipCode.Neighbourhood.LocationId、NeighbourhoodZipCode.ZipCode.LocationId)。

只是想我会继续编辑这个问题,并编辑关于我目前所处的位置。我开始怀疑带有自引用 FK 的 TPH 是否可能。

编辑

所以我发现了上面的错误,那是因为我错过了 Neighbourhood-ZipCode 多对多的连接表。

添加连接表(并将导航映射到该表)解决了上述错误。

但现在我得到这个错误:

错误 3032:从第 373、382 行开始映射片段时出现问题:条件成员“Locations.StateLocationId”具有重复的条件值。

如果我查看 CSDL,这里是“CountyState”的关联映射(一个州有很多县,一个县有 1 个州):

<AssociationSetMapping Name="CountyState" TypeName="Locations.CountyState" StoreEntitySet="Locations">
   <EndProperty Name="State">
      <ScalarProperty Name="LocationId" ColumnName="StateLocationId" />
   </EndProperty>
   <EndProperty Name="County">
      <ScalarProperty Name="LocationId" ColumnName="LocationId" />
   </EndProperty>
   <Condition ColumnName="StateLocationId" IsNull="false" />
</AssociationSetMapping>

Condition ColumnName="StateLocationId"是抱怨的,因为ZipCodeState联想也是这个条件。

但我不明白。所有实体的鉴别器都是唯一的(我已经三重检查),我会认为这是一个有效的场景:

  1. 县有一个州,用 StateLocationId(Locations 表)表示
  2. ZipCode 有一个单一的状态,由 StateLocationId(Locations 表)表示

这在 TPH 中无效吗?

4

1 回答 1

5

所以我解决了我的一些问题,但我碰上了砖墙。

首先,当您在数据库端创建自引用 FK 时,当您尝试“从数据库更新模型”时,Entity Framework 会将这些导航属性添加到主要基本类型,因为它没有明确的 TPH 意义 - 您需要在模型端执行此操作。

但是,您可以手动将导航属性添加到子类型。

WRT这个错误:

错误 3032:从第 373、382 行开始映射片段时出现问题:条件成员“Locations.StateLocationId”具有重复的条件值。

那是因为我有一个名为“Location_State”的 FK,我试图将其用于“ZipCode_State”关系和“City_State”关系——这不起作用(仍然不知道为什么)。

所以为了解决这个问题,我不得不添加额外的列和额外的 FK——一个称为“ZipCode_State”,另一个称为“City_State”——显然它必须是 navs 和物理 FK 之间的 1-1。

Location.LocationType 没有默认值并且不能为空。存储实体数据需要列值。

那是我的鉴别器领域。在数据库端,它不可为空

我阅读了有关此问题的线程,他们说您需要将关系从 0..* 更改为 1..* - 但我的关系已经是 1..*。

如果您查看我上面的“位置”实际数据库表,所有 FK 都可以为空(它们必须是)。因此我开始想知道我的关系是否应该是 0..*。

但由于 TPH,它们可以为空 - 并非所有“位置”都会有“状态”。但是如果那个位置是一个“城市”,那么它必须有一个“国家”。

这个 SO 问题进一步安慰了我的感受:ADO EF - TPH 中派生类型之间的错误映射关联

我实际上正在尝试这种解决方法(在我遇到它之前),但这种解决方法对我不起作用。我什至尝试将所有关系从 1..* 更改为 0..*,但仍然没有运气。

在这里浪费了太多时间,我又回到了TPT。

归根结底,如果使用 TPH,我将拥有一张大得离谱的表,其中包含大量冗余、可为空的列。JOIN-wise,它更有效。但至少对于 TPT,我不需要具有可为空和自引用的 FK。

如果有人有解决此问题的方法,请告诉我。但在那之前,我坚持使用 TPT。

于 2010-11-26T05:46:16.447 回答