1

如果我有这样的 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 给出此错误三次(一次用于基本实体,一次用于两个派生实体):

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

我按照这里的例子。

发生错误是因为我将鉴别器作为数据库中 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。

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

4

1 回答 1

1

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

在数据库端:

位置评分:

  • LocationScoreId:身份,PK
  • 位置 ID:FK
  • LocationId/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;

这就是我现在要做的。

于 2011-01-13T03:34:30.480 回答