【问题标题】:Is it a bad idea that every entity inherits from one base entity?每个实体都从一个基础实体继承是一个坏主意吗?
【发布时间】:2013-03-31 14:58:35
【问题描述】:

如果我让每个类都继承自提供他的键/id 的基类,会不会有问题(或者可能是个坏主意)? 这是在实体框架中的代码优先设计中

class MyObject
{
[Key]
public int Id { get; set; }
}

class Person : MyObject {...}
class Message : MyObject {...}
class Whatever : MyObject {...}

我想这样做是因为发生了很多事情,我希望两个/三个类(例如)从某个基类继承,而我不负责提供 id 的那个基类。

具体例子,对比一下:(实际场景)

class Recipient
{
[Key]
public int RecipientId { get; set; } // I want to avoid this
public string DisplayName { get; set; }
}

class Person : Recipient {...}
class Group : Recipient {...}

对此:(我想要实现的目标)

class MyObject
{
[Key]
public int Id { get; set; }
}

class Recipient : MyObject
{
public string DisplayName { get; set; }
}

class Person : Recipient {...}
class Group : Recipient {...}

【问题讨论】:

    标签: entity-framework inheritance primary-key


    【解决方案1】:

    我知道已经有一段时间没有提出这个问题了,无论如何我都会发布答案。

    到目前为止,我完成的代码优先项目已经数不胜数,并且我总是最终为我的实体创建了一个抽象基类。原因很简单,总有一些你认为应该存在于所有实体中的字段,Id当然是最明显的。

    此外,当您添加一个基类(或就此而言的接口)时,您突然允许您的 DbContext 对该抽象进行操作。我几乎总是向这个基类添加事件(如 OnLoad、OnSave、OnDelete),我将它们保留为虚拟,然后为我的 DbContext 覆盖 SaveChanges 方法并为受影响的实体调用适当的事件。

    所以我的回答是否定的,向您的 EF 类添加基类没有害处。但是就像上面的一些答案所说的那样,如果它对于 Id 列来说是微不足道的,那么也许你还不如在你的所有课程中重复这一行(4 个带有基本 cmets ;))。

    【讨论】:

    • 看到您的答案出现在这里让我意识到我自己对这个主题的看法同时发生了变化。我现在倾向于同意你的看法。另一个 SO 问题和我自己的项目导致我得出的一个结论是,EF 类模型的首要职责是服务于数据层问题。其中之一可以是识别或审计等横切关注点,通过抽象基类可以轻松实现。
    【解决方案2】:

    我的问题是why你想这样做......

    I don't see any real reasons to want to 'decouple' base class for the sake of 'ID-ing' alone。您所节省的只是一行代码。否则,您将不会在查询中使用该类(因为它实际上不代表任何内容),但您仍然必须小心“继承” - 因为您的代码,使用 TPC 场景会导致额外的表(对于所有“非-abstract' 类) - 所以我可能会把它设为abstract 只是为了确定。也不要将它定义为DbSet(这应该让它几乎保持“雷达”,就像界面一样)。

    如果您已经有另一个基类——这似乎是“ID”的理想场所——但这一切都是非常个人化的。

    ...简而言之-I haven't seen any major issues with it (just make it abstract and off DbSet)-尽管equally I don't see any gains from it。 IMO Entities / POCO 是 C# 对象 - 但毕竟提供了一些有意义的底层数据 - 我喜欢这样看待它们(也适用于任何其他类,而不仅仅是实体 / POCO)。

    【讨论】:

    • 所以,明确地说,你喜欢做那个基类的想法还是不喜欢?
    • 我喜欢你喜欢的 :) 底线没关系——它是“化妆品”——我认为这是一种矫枉过正——但如果它能让你解放思想,那就是你喜欢的想法它 - 一切都很好 - 只要记住限制
    • 添加 - 我认为“基类”应该有“更多”添加到“合同”而不仅仅是“ID” - 但我看到很多人这样做,所以我想这是个人喜好
    【解决方案3】:

    我对此有复杂的感觉。

    专业版

    • 它包含 DRY 原则(不要重复自己)。

    缺点

    • 它违反了继承的目的,即表达“是”关系(客户“是”人)。说 Person “是”基础对象在业务领域中毫无意义。它不表达任何业务逻辑。最终,由于 C# 不支持多重继承,因此拥有基类型可能会阻止其他继承策略。
    • 它混合了业务逻辑和 DAL 实现。基类中的字段与业务领域无关。拥有Id 纯粹是 DAL 事务。 (对于经常使用基本类型的 InsertDateTime 等值也是如此)。

    我倾向于不这样做。如果您希望您的实体有共同点,我会使用界面。这是相当多的工作,我知道。而且它看起来并不 DRY,但我认为 DRY 原则应该定义为“不要不必要地重复自己”。

    如果您仍然决定使用基类,我发现确保它不会成为实体模型(实体框架已知的模型)的一部分是有益的。如果是这样,您必须确保 EF 使用 TPC,并且不可能使用其他继承模型。因此,只映射派生类型,EF 永远不会知道基类型,也永远不会尝试实现和继承策略。

    【讨论】:

      【解决方案4】:

      在我看来,这会导致一切复杂化。例如,您想引用 userId,但由于超类,您的表都有 id。那么现在你必须在你的类中添加这样的东西

      @AttributeOverrides(值 = { @AttributeOverride(name = "id", column = @Column(name = "passwordTokenId", nullable = false)), @AttributeOverride(name = "name", column = @Column(name = "token", nullable = false)) })

      它并没有在这里结束。尝试在休眠中映射关系怎么样...你开始想知道这个 id 是类 Book 还是类 Person

      但是当你的类定义如下时很好

      公共类客户端扩展人 公共类 Broker 扩展了 Person

      并且类 Person 被定义有 String firstName 和 String lastName .. 再次 DRY 原则

      我都试过了,我喜欢保持简单(KISS)。就像上面那位先生说的那样,它包含 DRY,但它也违反了 (KISS).. 我同意最后一位先生的观点,我喜欢你喜欢的 :) 所以跟随你的直觉

      【讨论】:

        猜你喜欢
        • 2020-05-25
        • 1970-01-01
        • 2011-12-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-08
        • 2014-09-02
        相关资源
        最近更新 更多