【问题标题】:It is possible to use child class to implement Separation of concerns using EF Core?可以使用子类使用 EF Core 实现关注点分离吗?
【发布时间】:2020-06-06 08:14:03
【问题描述】:

我的目标是使用 DBContext 异步加载相关实体。

让我们想象两个项目。第一个名为MyApp.Domain 并包含域实体。

namespace MyApp.Domain
{
    public class PlanPage
    {
        public Guid Id { get; set; }
    }
}
namespace MyApp.Domain
{
    public class PlanPageDay
    {
        public Guid Id { get; set; }
        public Guid PlanPageId { get; set; }
    }
}

第二个项目名为MyApp.Infrastructure.EntityFramework,包含投影实体到数据库的配置。它还包含扩展领域实体并实现实体框架特定逻辑的类。

namespace MyApp.Infrastructure.EntityFramework.Models
{
    public class PlanPageEntity : PlanPage
    {
        private readonly ApplicationDbContext _applicationDbContext;

        protected PlanPageEntity(ApplicationDbContext applicationDbContext)
        {
            _applicationDbContext = applicationDbContext;
        }

        public ICollection<PlanPageDay>? Days { get; set; }

        public async Task<ICollection<PlanPageDay>> GetDays()
        {
            return Days ??= await _applicationDbContext.PlanPageDays
                .Where(pd => pd.PlanPageId == Id)
                .ToListAsync();
        }
    }
}

这个例子的目的很简单。我们将基础设施代码与域代码分开。看看我们打算如何使用这个概念:

// Entity initializing code. Placing somewhere in domain logic.
var plan = new PlanPage(/*some constructor arguments*/);

// Entity loading code. Placing somewhere in infrastructure implementation.
public async Task<PlanPage> GetPlanPage(Guid id)
{
    return await _applicationDbContext.Set<PlanPageEntity>().FindAsync(id);
}

请注意,我们告诉实体框架使用子类 (PlanPageEntity),以便它可以处理所有可以处理的特定事情。

问题是:是否可以配置 EF 以便我们使用这个概念?

【问题讨论】:

  • 您应该定义独立于域实体的 ef 实体。使用映射器在它们之间进行映射,但没有继承。
  • 这破坏了主题概念。目标是在域内提供加载器。 Mapper 需要与原始对象分开构造新对象。
  • 我完全同意 Rufo 爵士的观点:将域逻辑中的模型与数据访问模型混合是一个坏主意。你的头疼只会越来越严重,这听起来像是一场维护噩梦。
  • 感谢您的意见。然而,对我来说,这是可悲的。这个概念看起来是一个很好的解决方案。在这种情况下,我不得不寻找另一种实现方式。
  • @Xerillio,你能发表一个合理的反驳作为答案吗?我不是这个想法的唯一支持者,我想为其他寻求解决方案的人解决这个问题。

标签: c# entity-framework design-patterns orm


【解决方案1】:

根据要求,这里有一些关于我在 cmets 中的观点的详细信息。


我认为您当前的方法是一个坏主意的主要原因是它违反了separation of concerns 设计原则:当您将域模型与数据访问模型混合时,您的域逻辑完全取决于您如何建模数据库中的数据。这很快限制了您的选择,因为数据库可能对您如何建模与您要实现的域逻辑不匹配的数据有一些限制,并且使维护变得困难。例如。如果您决定将一个数据库表拆分为两个,那么您可能面临一项艰巨的任务,以使您的域逻辑与这两个新模型/表一起工作。此外,如果不提前考虑,在您的数据库中进行性能优化很容易成为一场噩梦 - 您不应该在必要之前花时间考虑优化您的系统。

我知道这有点抽象,因为我对您的域了解不多,但我相信我可以找到更多反对它的论据。


相反,将数据访问模型(通常是所有外部数据模型)与域模型分开可以更容易维护:如果您需要对数据库进行一些更改,您只需更新映射从您的数据访问模型到您的域模型的数据 - 您的域逻辑中的任何内容都不需要更改。

在您给出的示例中,您已经在逻辑上将域模型和数据访问模型分成两个独立的项目。那么为什么不遵循这个想法并在两者之间使用绑定/映射层将两者分开呢?

【讨论】:

    【解决方案2】:

    是否可以配置 EF 以允许我们使用这个概念?

    是的。本质上,您拥有 DTO,并且您的实体源自您的 DTO。因此,当您获取实体时,您可以直接返回它。但是如果你不能附加一个非实体,那么你就必须映射它。这会带来不便,并且像 99.999% 的定制实体和存储库设计一样,最终会浪费时间。

    这有点类似于 EF 已经为您做的事情。从不了解持久性的实体类开始,并为需要它们的场景引入持久性感知运行时子类型,这基本上只是延迟加载。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多