繁体   English   中英

实体框架6.0实现与POCO的实现

[英]Entity Framework 6.0 Decoupling Implementing From POCOs

假设我有几个基本对象和接口:

interface ICar
{
  int Id { get; set; }

  int DriverId { get; set; }

  IDriver Driver { get; set; }
}

class Car: ICar
{
  int Id { get; set; }

  [ForeignKey("Driver")]
  int DriverId { get; set; }

  IDriver Driver { get; set; }
}

如果我使用“Driver”的实现类而不是“IDriver”,一切都很高兴(所以我们忽略了我缺少所有其他值的附加配置),但是使用IDriver最终会出现错误:

属性“Driver”无法配置为导航属性。 该属性必须是有效的实体类型,并且该属性应具有非抽象的getter和setter。 对于集合属性,类型必须实现ICollection,其中T是有效的实体类型。

据我所知,实体实际上并没有以任何方式支持这一点,我的选择是:

  • 很难将我的POCO接口连接到实体,为可测试性和可移植性带来了麻烦。
  • 在我的POCO和实体对象(bleh)之间添加过渡层。
  • 抛出实体,用一些讨厌的Linq2SQL实现来解决这个问题(虽然Linq2SQL抱怨EntityRefs,它可以与EntitySets和接口一起运行!)。
  • 找到另一个ORM,它允许我从我的实施数据提供者中正确地抽象我的POCO。

或者我在这里遗漏了什么?

我做过几次这样的事。 如果您希望您的类完全独立,没有任何特定于Entity Framework的内容,那么您将不得不进行一些小的更改。 这是我做的:

  • 创建表示域实体的类​​。 我是在完全独立的装配中完成此操作(出于各种原因),但您不必这样做。
  • 引用带有类的命名空间,并将它们的集合添加到DbContext中。
  • 使用Entity Framework的Fluent Configuration API来映射您的类型 及其关系

最后一部分意味着你可能无法使用像[ForeignKey]这样的属性,因为它们中的许多都存在于System.Data.Entity中,此时你正在使用Entity Framework的东西,所以你不妨接受耦合。

这确实意味着你将不得不做更多的工作来建立关系,但它并不是太糟糕,当你完成后你的域类完全独立于实体框架,允许你模拟它进行测试或交换它非常无痛地用于另一个ORM。

您没有将POCO耦合到EF,它是另一种方式并且完全合法,因为域对象是应用程序的基本构建块。 类似于整数,字符串等...你不会“接口”int,不是吗? 例如,在任何时候你扔EF并取NH,这根本不会影响你的POCO。

现在,另一方面,自定义DbContext和业务类是创建接口所需的东西。 这样,您可以模拟它们以用于测试目的并更改实现。

还有一件事 - 不要让自己陷入在自编写数据访问层中从业务层中抽象EF的想法。 虽然这是可以实现的,但它也会对您的业务层实施施加大量限制。 你必须发明自我折磨技术来编写查询,否则你需要5秒的时间。

在我看来,理想的依赖图,经过大量的实验我想出来了,现在看起来像这样 在此输入图像描述

域对象,业务和上下文接口是应用程序的核心。 其他层彼此独立,因此是可测试的。

请注意,这里的业务层依赖于EF,如果我决定从EF切换(高度怀疑它),我将不得不移植我的业务类。 我相信,这是一个非常不可能发生的事件,并且为我在商务课程中提供的所有舒适性付出的代价很小。

您不希望为实体创建接口,因为您最终会得到头部接口,因此接口根本不是抽象,并且没有什么价值。 如果您创建角色接口,那么您可以轻松地在测试中删除实现以返回您希望的实体。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM