使用每个层次结构表映射片段异常(实体框架 4)

发布于 2024-10-11 21:43:25 字数 1454 浏览 7 评论 0原文

如果我有这样的 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。

你们能想到另一个解决方案吗?

If i have SQL Server tables like this:

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

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

Technically this is mapped as a Location 1..0..* Score, but with the PK of LocationId/IsSingleLevel, it's a Location 1..0..2.

When i drag this on the EDMX, set everything up as expected (abstract entity, remove discriminator from base entity, etc).

EF give this error three times (one for base entity, and one for the two derived entities):

Error 6 Error 3025: Problem in mapping fragments starting at line 2146:Must specify mapping for all key properties (LocationScore.LocationId, LocationScore.IsSingleLevelScore) of table LocationScore.

I followed the example here.

The error occurs because i have the discriminator as part of the PK in the database, and discriminators are not mapped on the model, so i get the error.

I can't have LocationId as the only field in the PK, because then a location could only have 1 score, i need it to have two scores (one single level, one overall).

The end result is i want to be able to do this:

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

Where LocationOverallScore and LocationSingleLevelScore are derived entities from the LocationScore base (abstract entity).

Is TPH not the right design here? Is my database design wrong? The aim is i don't want to have 2 physical tables for the different scores - as the table is huge, and i don't want to repeat the columns.

There's two possible workarounds i can think of:

1 - Make a view (LocationScore), which UNION's the two tables (so it would return 2 rows per LocationId) - but i still don't think i can "TPH" this. I don't want to manually perform the JOIN, i want to eager load.

2 - Add an IDENTITY column to Score, and this can be the PK.

Can you guys think of another solution?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

べ映画 2024-10-18 21:43:25

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

在数据库方面:

LocationScore:

  • LocationScoreId:IDENTITY,PK
  • LocationId:
  • LocationId/IsSingleLevelScore上的FK唯一索引

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

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

创建了 Location -> 之间的关联LocationOverallScore,位置-> 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;

这就是我现在要做的。

I found a solution. I'm not 100% happy with it, but it does satisfy my requirement of not having two tables.

In the database side:

LocationScore:

  • LocationScoreId: IDENTITY, PK
  • LocationId: FK
  • Unique Index on LocationId/IsSingleLevelScore

I imported that into my EDMX - and included the LocationId FK (i never usually do this - but it's required in this instance).

Created the derived entities, mapped the fields, set the discriminator.

Created an association between Location -> LocationOverallScore, Location -> LocationScore (based on LocationId referential constraint).

All works fine.

The one downside is that because LocationId is not part of the PK on the LocationScore table, it's a 1..* between Location and LocationOverallScore, when in reality it should only be a 1..1.

I enforce this business requirement in the model via a hook property:

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(); }
   }
}

So the .SingleOrDefault() will throw an exception if there is more than one record - which there never will be, because of the unique index.

So i can now do this:

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

That's what i'll be going with for now.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文