【问题标题】:Mapping fragments exception with Table-per-Hierarchy (Entity Framework 4)使用 Table-per-Hierarchy 映射片段异常(实体框架 4)
【发布时间】:2011-06-08 05:19:51
【问题描述】:

如果我有这样的 SQL Server 表:

Location
----------
LocationId int PK 
Field1 int
Field2 int
etc

Score
------------------------------------
LocationId int PK, FK
IsSingleLevel bit PK (discriminator)
Field1 int
Field2 int
etc

从技术上讲,这被映射为位置 1..0..* 分数,但对于 LocationId/IsSingleLevel 的 PK,它是位置 1..0..2。

当我将它拖到 EDMX 上时,按预期设置所有内容(抽象实体、从基本实体中删除鉴别器等)。

EF 给出此错误 3 次(一个用于基础实体,一个用于两个派生实体):

错误 6 错误 3025:从第 2146 行开始映射片段时出现问题:必须为表 LocationScore 的所有关键属性(LocationScore.LocationId、LocationScore.IsSingleLevelScore)指定映射。

我按照here的例子。

发生错误是因为我将鉴别器作为数据库中 PK 的一部分,并且鉴别器没有映射到模型上,所以我得到了错误。

我不能将 LocationId 作为 PK 中的唯一字段,因为这样一个位置只能有 1 个分数,我需要它有两个分数(一个单级,一个整体)。

最终结果是我希望能够做到这一点:

Locations.Include("LocationOverallScore").Single();
Locations.Include("LocationSingleLevelScore").Single();

其中LocationOverallScoreLocationSingleLevelScore 是从LocationScore 基(抽象实体)派生的实体。

TPH 不是这里的正确设计吗?我的数据库设计错了吗?目的是我不想为不同的分数设置 2 个物理表 - 因为表很大,我不想重复列。

我能想到两种可能的解决方法:

1 - 创建一个视图 (LocationScore),其中 UNION 是两个表(因此每个 LocationId 将返回 2 行) - 但我仍然认为我不能“TPH”这个。我不想手动执行 JOIN,我想立即加载。

2 - 将 IDENTITY 列添加到 Score,这可以是 PK。

你们能想出另一种解决方案吗?

【问题讨论】:

    标签: sql-server entity-framework database-design entity-framework-4 table-per-hierarchy


    【解决方案1】:

    我找到了解决方案。我对它不是 100% 满意,但它确实满足了我没有两张桌子的要求。

    在数据库端:

    LocationScore:

    • Lo​​cationScoreId:身份,PK
    • Lo​​cationId:FK
    • Lo​​cationId/IsSingleLevelScore 的唯一索引

    我将它导入到我的 EDMX 中 - 并包含 LocationId FK(我通常从不这样做 - 但在这种情况下是必需的)。

    创建派生实体,映射字段,设置鉴别器。

    在 Location -> LocationOverallScore、Location -> LocationScore 之间创建关联(基于 LocationId 引用约束)。

    一切正常。

    一个缺点是因为 LocationId 不是 LocationScore 表上 PK 的一部分,它是 Location 和 LocationOverallScore 之间的 1..*,而实际上它应该只是 1.. 1.

    我通过钩子属性在模型中强制执行此业务需求:

    public class Location
    {
       // EF navigational properties - required
       public ICollection<LocationOverallScore> LocationOverallScores { get; set; }
       public ICollection<LocationSingleLevelScore> LocationSingleLevelScores { get; set; }
    
       // Hook properties
       public LocationOverallScore OverallScore
       {
          get { return LocationOverallScores.SingleOrDefault(); }
       }
       public LocationSingleLevelScores SingleLevelScore
       {
          get { return LocationSingleLevelScores .SingleOrDefault(); }
       }
    }
    

    因此,如果有多个记录,.SingleOrDefault() 将抛出异常 - 由于唯一索引,永远不会有。

    所以我现在可以这样做了:

    var location = ctx.Locations.Include("LocationOverallScores").Single();
    var overallScore = location.OverallScore;
    

    这就是我现在要做的。

    【讨论】:

    • IDENTITY 和FK 一起作为Score 的PK 是否可行?
    • @Craig Stuntz - 我会尝试(当我到办公室时)并告诉你。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-29
    • 2013-04-04
    • 2014-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-01
    相关资源
    最近更新 更多