存储库,管道,业务逻辑和域模型 - 我如何将它们组合在一起?

时间:2011-05-20 15:41:29

标签: c# .net asp.net architecture domain-driven-design

我正在设计N层应用程序,我遇到了一个您可能有解决方案的难题。表示层是MVC。

我的ORM是使用LinqToSQL执行的 - 它是一个独立的项目,为存储库提供服务。

每个reporsitory都有一个界面和至少1个具体实现。

存储库具有以下方法:FindAll(), Save(T entity), Delete(int id)

FindAll()返回某种类型的IQueryable,这意味着它返回我可以应用过滤器的查询。

ORM映射已使用Database First方法进行,其中首先创建表,然后由SQL Metal生成类。

我添加了一个与存储库一起使用的Pipeline图层。它将更多过滤器应用于查询。例如。 OrderRepository.FindAll().Where(o => o.CustomerId == 10)

Pipeline还会返回某种类型的IQueryable,这意味着我可以将它传递到图层的更多位置并使用它做更多的事情。

此时我想转移到BusinessLogic层,但我不想再使用实体模型了,我想将实体模型转换为域模型。这意味着我可以向模型添加验证并在表示层中使用该模型。模型不能在MVC项目中定义,因为它依赖于表示层,所以这是一个no。

我很确定业务逻辑(行为)和模型必须与管道,数据和表示层分开存储。问题是在哪里?

例如,管道有三种方法: 1. FindByCustomerId 2. FindByOrderId 3. FindBySomethingElse

所有这些方法都返回了IQueryable of Order。我需要将其转换为域模型,但我不希望每个方法都这样做,因为它不可能是主要的。

我觉得这个模型非常强大且可扩展。我只是看不到从实体到域模型映射的最佳位置,反之亦然。

谢谢

5 个答案:

答案 0 :(得分:13)

首先,如果您在此处应用域驱动设计原则,则不得在应用程序中使用BusinessLogic层。所有业务逻辑都应该存在于您的域模型中。

但使用LinqToSQL很难实现,因为它不支持继承映射,您必须处理部分类以将业务逻辑放入您的域。所以我强烈建议考虑从LinqToSQL迁移到NHibernate或Entity Framework Code First。在这种情况下,您也不必将持久性模型转换为域模型,反之亦然。

如果您仍想进行转换,可以查看Automapper

答案 1 :(得分:12)

从域驱动的角度来看,您需要工厂将“数据库实体”转换为域模型实体。

当您考虑在管道末端将“数据库实体”转换为域模型实体时,您应该意识到在转换为域模型实体(投影)后,您将无法使用IQueryable投影功能将触发表达式树的执行。例如,如果您为客户数据库实体调用FindAll,然后将IQueryable转换为(或将其投影到)客户域实体,它将执行(请求整个表的内容)。

答案 2 :(得分:8)

这就是我进行N-Tier项目的方式。这种架构具有很大的关注点。听起来你已经走向了这个方向。

在Mvc项目中是你所有常用的对象(控制器,视图模型,视图,帮助器等)。非常坦率的。所有视图都是强类型的。加上我修改过的T4模板,可以生成Controllers,Views和ViewModels。

在业务模型项目中,我拥有所有业务对象和规则,包括定义数据存储库功能的接口。我没有为每个业务对象/表创建一个存储库,而是希望按功能对其进行分组。与博客相关的所有对象都在一个存储库中,而与照片库相关的所有对象都在一个单独的存储库中,而日志记录可能位于第三个存储库中。

您可以将管道图层放在此处。

在Data项目中,我实现了那些数据存储库接口。您可以使用Linq2SQL而无需使用部分类。扩展这些Linq2SQL分部类意味着您已将ORM绑定到域模型。你真的不想做的事情。您希望将这些生成的数据类保留在数据域中。以下是返回BusinessModel对象的Linq2SQL选择示例。

from t in Table
where t.Field == keyField
select new BusinessModel.DataObject
{
  Id = t.Id,
  Field1 = t.Field1,
  Field2 = t.Field2
}

如果我是你,我会使用CodeFirst方法查看EntityFramework 4.1或使用NHibernate。这些中的任何一个都会将您的数据模型映射到域模型。然后将域模型映射到视图模型,您可以使用AutoMapper或编写自定义代码或编写将为您生成映射代码的T4模板。

您可以将dbml文件生成的代码作为业务对象的起点。

答案 3 :(得分:3)

除了xelibrion的评论之外,您还可以查看LightSpeed以满足您的ORM需求。您目前正在使用LinqToSQL,因此您应该非常直接地找到Lightspeed,因为它使用相同的想法。

http://www.mindscapehq.com/products/lightspeed

如果您可以将数据映射到更符合您更高级别所需表单的模型,那么希望您可以简化操作。系统复杂性越低,错误的范围就越小。

答案 4 :(得分:0)

  

所有这些方法都返回IQueryable   订购。我需要将其转换为   域模型,但我不想这样做   每种方法都不会如此   mainteinable。

这不是一个真正的评估,可能阻止您看到正确的解决方案。