我目前使用Table Per Type(TPT)实现了Entity Framework 4.0模型,但是存在一些性能问题(许多LOJ / CASE语句),以及两个特定域区域之间的问题映射(许多一对多)。
我决定试用TPH。
我有一个名为“位置”的实体,它是抽象,是所有其他实体的基础。
然后我有“国家”,“城市”,“州”,“街道”,等等都来自位置。
“ LocationType ”是 dicriminator 。
该部分工作正常,但我在尝试为派生类型定义导航属性时遇到问题。
例如,“州”只有一个“国家/地区”,所以我应该可以这样做:
var state = _ctx.Locations.OfType<State>().Include("Country").First();
var countryForState = state.Country;
但是这需要在“州”派生实体上称为“国家”的导航属性。我该怎么做呢?当我从数据库生成模型时,我有一个表,所有FK都指向同一个表中的记录:
(注意:我在数据库中手动创建了这些FK)。
但是FK被定位为“位置”实体的导航,那么如何将这些导航属性下移到派生实体?我不能复制+粘贴导航,我不能“创建新的导航属性”,因为它不会让我定义开始/结束角色。
我们如何做到这一点?
TPH还不清楚我们是否可以先建立模型,或者我们必须从数据库开始,修复模型然后重新生成数据库。我还没有在互联网上找到一个关于如何使用TPH定义儿童导航的好例子。
注意:我不想先执行代码。我目前的解决方案是TPT与EDMX,以及纯POCO,我希望不影响域模型/存储库(如果可能),只需更新EF模型/数据库。
修改
仍然没有解决方案 - 但是我试图先做模型,然后做Add - &gt;新协会实际上允许我向派生实体添加导航。但是当我尝试“从模型中生成数据库”时,它仍然会尝试为“Location_Street”,“Location_Country”等创建表。这几乎就像TPH不能先完成模型。
修改
这是我目前的模特:
我目前得到的验证错误:
错误1错误3002:映射问题 片段从行开始 359:潜在的运行时违规 表位置的键 (Locations.LocationId):列 (Locations.LocationId)映射到 EntitySet NeighbourhoodZipCode's 性能 (NeighbourhoodZipCode.Neighbourhood.LocationId) 在概念方面,但他们没有 形成EntitySet的关键属性 (NeighbourhoodZipCode.Neighbourhood.LocationId, NeighbourhoodZipCode.ZipCode.LocationId)。
我以为我会继续编辑这个问题,编辑关于我目前所处的位置。我开始怀疑TPH是否有可能自我引用FK。
修改
所以我想出了上面的错误,那是因为我错过了很多次的Neighborhood-ZipCode的连接表。
添加连接表(并将导航映射到该表)解决了上述错误。
但是现在我得到了这个错误:
错误3032:映射问题 片段从第373行开始, 382:条件成员 'Locations.StateLocationId'有 重复的条件值。
如果我看一下CSDL,这里是“郡州”的关联映射(一个州有很多县,一个县有一个州):
<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
关联也是这种情况。
但我不明白。所有实体的鉴别器都是唯一的(我有三重检查),我认为这是一个有效的方案:
这在TPH中无效吗?
答案 0 :(得分:5)
所以我解决了一些问题,但是我碰到了一堵砖墙。
首先,当您在数据库端创建自引用FK时,当您尝试“从数据库更新模型”时,实体框架会将这些导航属性添加到主基本类型,因为它没有明确的意义TPH - 你需要在模型方面这样做。
但是,您可以手动将导航属性添加到子类型。
WRT此错误:
错误3032:从第373,382行开始映射片段时出现问题:条件成员的Locations.StateLocationId'具有重复的条件值。
那是因为我有一个名为“Location_State”的FK我试图用于“ZipCode_State”关系,以及“City_State”关系 - 这不起作用(仍然不知道为什么)。
所以要解决这个问题,我必须添加额外的列和额外的FK - 一个名为“ZipCode_State”,另一个名为“City_State” - 显然它必须是导航和物理FK之间的1-1。
Location.LocationType没有默认值且不可为空。存储实体数据需要列值。
这是我的鉴别领域。在数据库方面,不可为空。
我读了关于这个问题的帖子,他们说你需要将关系从0 .. *更改为1 .. * - 但我的关系已经是1 .. *。
如果查看上面的“Locations”实际数据库表,所有FK都可以为空(它们必须是)。因此我开始怀疑我的关系是否应为0 .. *。
但由于TPH,它们可以为空 - 并非所有“地点”都有“状态”。但如果该位置是“城市”,则它必须具有“州”。
这个问题让我的感受更加安慰:ADO EF - Errors Mapping Associations between Derived Types in TPH
我实际上正在尝试这种解决方法(在我遇到它之前),并且解决方法对我不起作用。我甚至尝试将所有关系从1 .. *更改为0 .. *,但仍然没有运气。
在这里浪费了太多时间,我已经回到了TPT。
在一天结束时,使用TPH我会有一个可笑的大表,有很多冗余的可空列。加入方式,效率更高。但至少对于TPT,我不需要有可空和自我引用的FK。
如果有人能解决这个问题,请告诉我。但在那之前,我坚持使用TPT。