我已经开始研究将驻留在单个服务器(包括数据库)上的 WebForms(不是 MVC)应用程序,并决定使用(我认为)非常标准的 N 层架构来设计它。
数据层
- 使用实体框架 4 和通用存储库/工作单元模式。
- 将广泛使用存储过程(这是权力赋予我的要求)。
- 持有对业务对象层的引用,以将数据传入/传出 BO。
业务对象“层”
- 代码优先的 POCO。
- 他们将拥有的唯一行为是验证内容(名称不为空,数量必须为正整数等)。
- 不引用任何其他层或关心数据的来源。
业务逻辑层
- 包含我的业务服务,它将充当 UI 和数据层之间的中间人,并执行其他业务“规则”,例如记录更改时的电子邮件通知等。
- 具有对数据层和业务对象层的引用。
- 将 BO 传入/传出 UI。
界面层
- 包含所有常见的 UI 内容 - Web 表单、javascript、样式表等。
- 引用业务逻辑和业务对象层。
几个问题......好吧,实际上很多:/
- 当应用程序要跨多个服务器,将使用 Web 服务,或者当传递给视图的数据是多种类型的业务对象的编译时,我可以看到使用 DTO 的优势,但是真的需要当所有东西都在同一台物理机器上时,将所有 BO 转换为 DTO,然后在 BLL 和 UI 之间传递它们?大多数 DTO 都是“复制、粘贴、将‘DTO’添加到类名末尾”的事情,所以这似乎是一种毫无意义的浪费时间?我最终得到的只是更高的维护成本和稍慢的性能(现在必须用相同的代码更新两个类而不是一个)。
- 假设在某些情况下需要 DTO,是否可以向 DTO 添加验证(即:名称不能为空,数量必须是正整数等)。?
- 使用 FluentValidation 之类的东西将验证代码分离到它自己的类库中是最好/更好的做法吗?如果我这样做了,那么 BO 基本上会变成 DTO,因为它们的行为为零……在这种情况下,我似乎最终会得到一个贫血的域模型?
- 当 BO 被 EF 使用时,数据层是否可以引用业务对象层?
看到我的服务“Find(predicate)”和“FindAll()”方法将使用相同的存储过程(提取所有记录),这是否意味着执行以下操作:
List<Foo> myFoo = FooService.Find( f => f.Country == "Australia" && f.Status = OrderStatus.New );
实际上会通过存储过程提取所有记录,并在事后执行过滤吗?在这种情况下,如何使用只检索所需记录的存储过程,同时允许使用 linq 表达式(需要允许 &&、||、!= 等)?这甚至是可能的吗(无需放弃存储过程)?