【问题标题】:Db Structure Issue with EFEF 的 Db 结构问题
【发布时间】:2017-12-06 13:00:03
【问题描述】:

我最近一直在搞乱实体框架代码,同时试图看看我能用它做什么。 我测试的一种情况是尝试复制以下数据库架构:

表格:

  • 播放器
  • 经理

Person 表保存基本数据名称、年龄等

球员表只保存与球员相关的信息:currentclubId、positionId 等 玩家的基本详细信息将通过与玩家 ID 和 PersonId 上的 Person 表的 1:1 关系提供。

Manager 表与 player 表非常相似,在 Manager Id 和 person Id 上与 Person Table 保持 1:1 的关系。

这个架构背后的想法是,一个人可以在整个职业生涯中成为球员和经理,我想避免重复基本细节。

我的问题是 EF 使用 Person 属性生成玩家模型。

public class Player {
    public Person Person {get;set;}
    .....    
}

因此,要获得玩家的名字,您必须调用 Player.Person.FirstName。 这个流程一开始还不错,但我开始看到 Player 和 Manager 查询存在性能问题,因为它们必须从两个表中获取。

有什么方法可以重构此架构以在不违反要求的情况下提高性能?

【问题讨论】:

  • 只获取您需要的数据?您可以包含或不包含相关实体。
  • 创建一个继承 Player 的新类并添加新属性。您可以向父级添加链接,但必须在添加新播放器时设置链接
  • @Sami 建立这种关系的原因是球员在他的职业生涯中可能是球员或经理,或两者兼而有之。我对重构的想法是创建一个历史表,并在其中指定该人是球队的球员还是经理,而不是当前版本

标签: c# sql sql-server database entity-framework


【解决方案1】:

由于您将每个班级放在一个单独的表格中,因此总是会有 3 个表格。因此,在任何查询中,您都会有一个 join 语句,这会导致您提到的性能问题。而且,实际上,您定义的域不需要在表格中分隔。它们只是一个有一些细微差别的对象。因此,最好将表合并为一个,并避免join 查询。为此,您有一些选择:

  1. 使用继承:使PlayerManager继承自Person并使用TBH方法。

  2. 使用 ComplexType:制作 PlayerManager 复杂类型(EF 会将它们视为 intstringenum 等)。

在这两种情况下,所有 3 种类型都只有一张表;而且根本不会有join

【讨论】:

  • 我不认为在 SQL 语句中加入连接本身就是一个性能问题,这就是为什么我怀疑他们只是拉出 Person 行(或集合)然后在循环遍历设置,导致延迟加载。
  • 绝对正确。答案基于提供的信息问题。根据这些信息,我唯一能猜到的是join 并且迭代对象和延迟加载关系,到目前为止。你不觉得吗? .顺便说一句,域(如所定义的)还不够复杂,无法在此处拥有 3 个表。因此,避免不必要的join 似乎是个好主意。
  • 消除对 Join 和子类型化人员的需求似乎是个好主意,但我经常发现,如果处理不当,EF 中的继承可能会出现问题。鉴于 OP 问题的性质,我目前不建议他采用实体继承等高级概念,尽管我承认这种方法可能是更好的最终解决方案。
  • 很公平。他们可以完全错过域:)
  • @Javad_Amiry TBH 方法意味着如果您有一个球员和经理人,那么您有重复的记录,即 Fname Lname 将为每种类型重复。
【解决方案2】:

根据您提供的图表中的架构,我期望类似 ...

public class Person
{   
   [Key]
   public int PersonId {get;set;}

   [ForeignKey("Player")]
   public int player {get;set;} // make this int? if a person can optionally be a player

   public virtual Player Player {get;set;}
   ...
}

然后,您将为 person 对象上的 manager 属性重复此属性模型。 完成此操作后,在查询数据库时,您应该使用 .Include() 以避免在“延迟加载情况”中递归子查询返回数据库。

例如:

var allJoes = Db.Persons
   .Where(p => p.Name.Contains("Joe"))
   .Include(p => p.Player)
   .Include(p => p.Manager);

您可以选择添加子选择以仅从数据库中的该数据中提取您需要的字段。

var joePieces = allJoes
    .Select(j => new { j.Name, j.Player.PlayerId, j.Manager.ManagerId });

最终结果是...的执行

var results = joePieces.ToArray();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-25
    • 1970-01-01
    • 1970-01-01
    • 2011-10-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多