实体框架(关于POCO,背景和DTO的问题)

nig*_*457 1 asp.net poco entity-framework-4

我在过去的几天里一直在阅读有关实体框架的内容,并且设法得到了一个使用它的公平想法,但我仍然有一些问题,其中一些可能看起来有点过于基本.为了透视,我在asp.net Web应用程序中使用实体框架4.0.如果您可以回答任何问题,请继续.

  1. 使用POCO模板可以获得什么好处.我理解,如果我希望得到持久性的无知并让我的实体清楚地了解与存储相关的任何信息POCO实体是可行的方法.在使用POCO实体时,我可以相对轻松地从实体框架切换到说NHibernate吗?除了疏松耦合之外,我有任何重要的理由去POCO实体.另外,如果我使用POCO,我最终会失去任何东西.在代理的帮助下,我仍然可以获得更改跟踪和延迟加载?

  2. 通常的做法是使用EF模型的实体作为数据传输对象或业务对象.例如,我有一个单独的类库用于我的实体模型.假设我正在使用MVP,我想要一个公司的员工列表.演示者将请求我的业务逻辑函数,该函数将查询实体模型以获取Employee列表,并将实体列表返回给演示者.在这种情况下,我的演示者需要引用EF模型.这是正确的方法吗?在我的asp.net web applciation的情况下,它不应该是一个问题,但如果我使用Web服务,这是如何工作的?这是走向POCO实体的原因吗?

  3. 假设Employee实体具有公司表的导航属性.如果我在'using'块中使用并包装数据上下文,并尝试访问BL中的导航属性,我假设我会得到一个异常.如果我关闭延迟加载并使用'include'linq查询获取实体,我是否也会得到异常?在之前的帖子中,有人建议我每个请求使用一个上下文,暗示即使我在BL中,上下文仍保持活动状态.我假设我仍然需要分离对象并将其附加到我的下一个请求的上下文中,如果我希望坚持我做出的任何更改?或者我应该用新的上下文再次查询对象并更新它?

  4. 这个问题更多地与组织文件/最佳实践有关,并且是我之前发布的问题的后续问题.当我使用基于实体的单独文件来组织我的数据访问层时,组织涉及多个表之间的连接的查询的最佳实践是什么.我对组织仍然有些模糊.尝试过在网上搜索但没有太多帮助.

Jef*_*ner 5

太棒的问题.我的第一个建议是以模式思考.照这样说...

  1. 你几乎已经掌握了使用POCO的优点.将业务对象(PO​​CO实体)与数据访问层分离有一些明显的优势.但主要原因就像你说的更改或修改以下层的能力.但是,使用POCO,您基本上遵循Code First(CF)方法.就个人而言,我认为它是并行编码,具体取决于您的软件开发生命周期.你仍然拥有数据或模型第一种方法所具有的所有花哨和口哨,因为你可以扩展DbContext,它是引擎盖下的ObjectContext.我读了一篇文章,我似乎无法发现,CF是Entity Framework的未来.最后,POCO的优点在于您可以在此处或其他地方合并验证规则.您还可以提供预测.假设您有出生日期,但您也想要Age属性.现在变得毫无疑问,因为映射到数据库时会忽略Age属性.
  2. 就个人而言,我为大型项目创建自己的业务对象(PO​​CO),这些项目往往具有自己的生命,其中变化是一种生活方式.另一个想法是可扩展性和可维护性.如果我选择在应用程序之间拆分功能,就像您提到的Web服务一样,现在可以从两个不同的位置提供功能.如果您已将业务对象和DAL封装在同一代码块中,则分离或可伸缩性现在变得有点复杂.但是,请考虑该项目.它可能很小,未来变化很小,所以不需要投掷手榴弹来杀死苍蝇.此时数据可能是首选方式,让edmx文件代表您的对象.所以不要嫁给一种技术或一种方法/模式.做你的时间和业务有意义的事情.
  3. 使用语句非常好.事实上,我最近已经转向将其包装在TransactionScope中.如果发生错误则回滚是固有的.接下来,要考虑的是UnitOfWork.UnitOfWork模式封装了数据上下文是您在其中工作的边界所需执行的快照.对于每个UnitOfWork,您都有一个要对其执行工作的主题.例如,员工.因此,如果您要保存员工信息以保持简单,您可以调用BL服务或存储库(无论如何).在那里传入Employee Id,在UnitOfWork下执行一些工作,它在构造函数中实例化或使用依赖注入(DI或IoC).Easy starter是StructureMap.在那里,服务对您的UnitOfWork(DbContext)进行必要的调用,然后将控制返回到上游(例如UI).
  4. 这里学习的最好方法是查看其他代码.我将从一些微软的例子开始.我将从Nerd Dinner(http://nerddinner.codeplex.com/)开始,然后再进行构建.

补充阅读:

是否使用原型模式

http://weblogs.asp.net/manavi/archive/2011/05/17/associations-in-ef-4-1-code-first-part-6-many-valued-associations.aspx

[编辑] NightHawk457,我非常抱歉没有回答你的问题.希望你想出来,但对未来的读者...

为了帮助每个人可视化,请使用域模型和存储库作为示例,想象下面的体系结构.请记住,有很多方法可以让猫皮肤变形,所以请将它自己制作出来,并且不要忘记上面的Grenade评论.

  • 数据层(数据访问):MyDbContext:DbContext,IUnitOfWork,其中IUnitWork收缩CRUD操作.
  • 数据存储库(数据访问/业务逻辑):MyDomainObjectRepository:IMyDomainObjectRepository,它通过Factory类或依赖注入接收IUnitOfWork.在CRUD操作上调用MyDomainObject验证.
  • 域模型(业务逻辑):使用[自定义]验证属性的MyDomainObject.阅读本文的优缺点.
  • MVVM/MVC/WCF(演示文稿/服务层):您选择了哪些附加层,您现在可以访问您的数据,这些数据可以很好地包装在自我封装其功能的较小模块中.然后,表示层(例如ViewModel,Controller,Code-Behind等)可以通过Factory类或依赖注入接收IMyObjectRepository.

提示:

  • 将连接字符串传递给MyDbContext,以便您可以重用MyDbContext.
  • MySQL不与System.Transactions.TransactionScope,发挥好例子.我不记得确切,但它是MySql不支持的东西.这使得测试有点困难,因为我们已经创建了这种级别的分离.
  • 为每个层创建一个测试项目,并至少测试一般功能/规则.
  • 每个域对象应至少使用ID字段扩展基础对象.此处也不要实现Key属性.域对象不应该描述体系结构,而应该将特定数据描述为实体.即使在Code First上,这也可以通过Fluent API实现.
  • 在创建MyDbContext时考虑泛型.;)阅读迭戈的帖子.
  • 在ASP.NET中,存储库很适合与ObjectDataSources一起使用.

正如您所看到的,IUnitOfWork和IMyDomainObjectRepository是公开上述层功能的接口的角色明显分离.作为一个例子,IUnitOfWork可以是NHibernate,Entity Framework,LinqToSql或ADO.NET,其中工厂类或依赖注入注册的更改都必须改变.仅供参考,我听说存储库也称为服务层.就个人而言,我喜欢第一个名字,不要与Web服务混淆.这个结构的下一个重要部分是实现数据库上下文(IUnitOfWork)的范围.一个简单的例子是一个ASP.NET页面,对于每个页面,每个存储库或该工作范围都有一个且只有一个IUnitOfWork.对于ViewModels,控制器等也是如此.因此,假设您需要使用两个存储库,即EmployeeRepository和HRRepository.然后,您可以在两者之间共享IUnitOfWork.为了跨页面,ViewModel或Controller边界,我们使用ID作为实体,然后从DB中提取它们并执行工作.您也可以跨越边界传递DTO并附加到上下文,但随后您开始失去图层分离.

要继续,POCO类不必自动生成.实际上,您可以从头开始创建实体类,并在OnModelCreating(DbModelBuilder mb)方法中的扩展DbContext类中执行映射.从这里开始,然后在这里注意其他资源,google Fluent API并阅读Diego的这篇文章.

至于验证,这是一个有趣的观点,因为如果可以在一个位置验证所有业务规则,那将是很好的.好吧,众所周知,这并不能很好地发挥作用.所以这是我的建议,尽可能在域对象中使用数据注释保持所有数据级别验证(即必需,范围,格式等),并在存储库中保留进程验证,并具有存储库的明确角色(即if(如果( isEmployee)这样做,否则).我说清楚,这样你就不想在两个不同的存储库中添加一个Employee,其中必须重复验证.要调用验证,请从此处开始.捕获ValidationResults并向上游发送MyRepositoryValidationException,其中包含可以呈现给表示层的验证错误集合(例如,需要Employee).尽管如此,不要忘记在表示层执行验证.例如,您不希望回发以确保员工拥有有效的电子邮件.

记住要平衡时间和精力与复杂性.对于简单的事情,请在您的EDMX文件中使用Data First或Model First.然后在其上放置一个存储库,该存储库还包含所有验证规则.