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

时间:2011-11-29 22:06:18

标签: asp.net entity-framework-4 poco

我在过去的几天里一直在阅读有关实体框架的内容,并且设法得到了一个使用它的公平想法,但我仍然有一些问题,其中一些可能看起来有点过于基本。为了透视,我在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. 这个问题更多地与组织文件/最佳实践有关,并且是我之前发布的问题的后续问题。当我使用基于实体的单独文件来组织我的数据访问层时,组织涉及多个表之间的连接的查询的最佳实践是什么。我对组织仍然有些模糊。尝试过在网上搜索但没有太多帮助。

1 个答案:

答案 0 :(得分: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. 这里学习的最好方法是查看其他代码。我从一些微软的例子开始。我从书呆子晚餐(http://nerddinner.codeplex.com/)开始,然后再建立起来。
  5. 补充阅读:

    Use prototype pattern or not

    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。阅读this了解优缺点。
    • MVVM / MVC / WCF 演示文稿/服务层):您选择了哪些其他图层,您现在可以访问您的数据,这些数据可以很好地包装在较小的模块中谁是自我封装他们的功能。然后,表示层(例如ViewModel,Controller,Code-Behind等)可以通过Factory类或依赖注入接收IMyObjectRepository。

    <强>提示:

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

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

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

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

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