I have a similar architecture in my MVC2 app. What I did:
BL returns a Person DTO that have Name, Surname and DoB (all those properties are a part of Person)
My Views work with Models, so I create specific models for each view. I would therefore have 2 Person models, ie. one with Name and Surname, other with Name and DoB.
The conversion between DTOs and models is done by a set of classes I call Adapters. In order to simplify code I use Automapper. This is a brilliant piece of code that will copy properties from your DTOs to Models by taking into account naming conventions and explicit configuration. Do take a look at is, as you might want to use it to populate DTOs from your EF classes.
Summing up, I have a consistent BL without any smells (this 'give me a subclass of this type' business is a bit of smell to me), and my views are working with strongly-typed models that contain only relevant data.
您没有要求这个(至少没有直接要求),但我不会将我的 BL 绑定到 EF - 事实上,我不会将它绑定到数据访问层全部。如果你这样做,任何想要使用你的 BL 的人也将被绑定到 EF。您可能需要考虑 依赖倒置。
A couple of things: firstly terminology. I'm not trying to be a terminology nazi - it's just that there's some subtle differences which might affect how you think about your problem.
DTO vs POCO
When you talk of a DTO (Data Transfer Object) it sounds more like a POCO (Plain Old CLR Object).
POCOs:
Are a simple data structure for passing information between layers.
Usually this happens within an application; specifically a .Net application (managed code).
They are usually designed with SRP (Single Responsibility Principle) in mind.
In this context (the design of a specific POCO) SRP would mean either a "business" driven case of use (i.e: to show a summary of 'person' data in search results) or a generic / data centric one (i.e: provide a 'person').
DTO:
Until recently I blindly assumed that POCO == DTO; and certainly a lot of people (I think) tend to talk about them that way; I then read Martin Fowler's definition of a DTO, which is different.
Where a POCO is used between layers of an application, a DTO is used between applications.
The rationale is that if you have to send data over the wire - and that call is expensive - then rather than making several calls to pass several objects/data/whatever you wrap them all into a single entity and make one call. That one entity is a DTO.
So, conceivably you might use a DTO to pass several POCO's to an external service.
The Answer to Your Question
When designing POCOs (and the interface between layers and components) at the top of your mind should be "why"? There's a few different views and motivations that you consider when designing your POCOs (and DTOs):
Responsibility: who "owns" the POCO? (i.e: what system owns the data within it).
Use Case: is the POCO there because it make sense in a general / generic way, or, is it there for a specific / specialized purpose?
Performance, and other runtime system qualities: DTO's are certainly influenced by performance considerations, and it's conceivable that similar thinking can be applied to POCO's when exchanging info between layers.
So, here's two approaches you might consider...
Responsibility Driven using Concrete POCOs
Design and build a POCO (as in an actual class or struct) that does the job you want; this will be along the lines discussed above ("business" or "generic / data centric").
This is how I currently do things. I often have a 'fat' POCO that defines an entity in it's entirety(sometimes including other POCOs), and a 'thin' POCO for use in lists. I also tend to use seperate POCOs for saving and updating.
While it makes sense to standardize why POCOs are designed the way they are (e.g: they are all driven by the domain model, and there's only one POCO per entity) - the truth is that you'll have different motivations from different directions; my advice is to give in to this otherwise you'll end up with a system that is not flexible, easy to maintain or performant.
Using Interfaces
This is a more 'pure' approach. Rather than have your application pass concrete POCOs around use interfaces instead. Then when you build implement a POCO it can implement as many of those interfaces as you like. For example:
You haven't asked for this (at least not directly) but I wouldn't tie my BL to EF - in fact I wouldn't tie it to the Data Access Layer at all. If you do, whatever wants to use your BL will be tied to the EF as well. You might want to consider Dependency Inversion.
发布评论
评论(2)
我的 MVC2 应用程序中有类似的架构。我做了什么:
BL 返回一个具有姓名、姓氏和 DoB 的 Person DTO(所有这些属性都是 Person 的一部分)
我的视图与模型一起使用,因此我为每个视图创建特定的模型。因此,我会有 2 人模型,即。一个包含 Name 和 Surname,另一个包含 Name 和 DoB。
DTO 和模型之间的转换是由一组我称为适配器的类完成的。为了简化代码,我使用Automapper。这是一段出色的代码,它将考虑命名约定和显式配置,将属性从 DTO 复制到模型。请查看 is,因为您可能希望使用它来填充 EF 类中的 DTO。
总而言之,我有一个一致的 BL,没有任何异味(这种“给我一个这种类型的子类”业务对我来说有点异味),并且我的观点是使用仅包含相关数据的强类型模型。
I have a similar architecture in my MVC2 app. What I did:
BL returns a Person DTO that have Name, Surname and DoB (all those properties are a part of Person)
My Views work with Models, so I create specific models for each view. I would therefore have 2 Person models, ie. one with Name and Surname, other with Name and DoB.
The conversion between DTOs and models is done by a set of classes I call Adapters. In order to simplify code I use Automapper. This is a brilliant piece of code that will copy properties from your DTOs to Models by taking into account naming conventions and explicit configuration. Do take a look at is, as you might want to use it to populate DTOs from your EF classes.
Summing up, I have a consistent BL without any smells (this 'give me a subclass of this type' business is a bit of smell to me), and my views are working with strongly-typed models that contain only relevant data.
有几件事:首先是术语。我并不是想成为一个术语纳粹分子 - 只是存在一些细微的差异,可能会影响您对问题的看法。
DTO 与 POCO
当您谈论 DTO(数据传输对象)时,它听起来更像是 POCO(普通旧 CLR 对象)。
POCO:
在这种情况下(特定 POCO 的设计),SRP 意味着“业务”驱动的使用案例(即:在搜索结果中显示“人员”数据的摘要)或通用/以数据为中心的使用案例(即:提供一个“人”)。
DTO:
直到最近我还盲目地认为 POCO == DTO;当然,很多人(我认为)倾向于这样谈论它们;然后我读了 Martin Fowler 对 DTO 的定义,这是不同的。
因此,可以想象您可以使用 DTO 将多个 POCO 传递给外部服务。
问题的答案
在设计 POCO(以及层和组件之间的接口)时,您首先想到的应该是“为什么”?在设计 POCO(和 DTO)时,您需要考虑一些不同的观点和动机:
因此,您可能会考虑以下两种方法...
使用具体 POCO 进行责任驱动
设计并构建一个 POCO(如在实际的类或结构中)来完成您想要的工作;这将遵循上面讨论的思路(“业务”或“通用/以数据为中心”)。
这就是我目前做事的方式。我经常有一个“胖” POCO 来完整地定义一个实体(有时包括其他 POCO),还有一个“瘦” POCO 用于列表中。我还倾向于使用单独的 POCO 来保存和更新。
虽然标准化 POCO 的设计方式是有意义的(例如:它们都是由领域模型驱动的,并且每个实体只有一个 POCO),但事实是,您将有来自不同方向的不同动机;我的建议是屈服于这一点,否则你最终会得到一个不灵活、不易于维护或性能不佳的系统。
使用接口
这是一种更“纯粹”的方法。而不是让您的应用程序在使用接口周围传递具体的 POCO。然后,当您构建实现 POCO 时,它可以实现您喜欢的任意多个接口。例如:
奖励点
您没有要求这个(至少没有直接要求),但我不会将我的 BL 绑定到 EF - 事实上,我不会将它绑定到数据访问层全部。如果你这样做,任何想要使用你的 BL 的人也将被绑定到 EF。您可能需要考虑 依赖倒置。
A couple of things: firstly terminology. I'm not trying to be a terminology nazi - it's just that there's some subtle differences which might affect how you think about your problem.
DTO vs POCO
When you talk of a DTO (Data Transfer Object) it sounds more like a POCO (Plain Old CLR Object).
POCOs:
In this context (the design of a specific POCO) SRP would mean either a "business" driven case of use (i.e: to show a summary of 'person' data in search results) or a generic / data centric one (i.e: provide a 'person').
DTO:
Until recently I blindly assumed that POCO == DTO; and certainly a lot of people (I think) tend to talk about them that way; I then read Martin Fowler's definition of a DTO, which is different.
So, conceivably you might use a DTO to pass several POCO's to an external service.
The Answer to Your Question
When designing POCOs (and the interface between layers and components) at the top of your mind should be "why"? There's a few different views and motivations that you consider when designing your POCOs (and DTOs):
So, here's two approaches you might consider...
Responsibility Driven using Concrete POCOs
Design and build a POCO (as in an actual class or struct) that does the job you want; this will be along the lines discussed above ("business" or "generic / data centric").
This is how I currently do things. I often have a 'fat' POCO that defines an entity in it's entirety(sometimes including other POCOs), and a 'thin' POCO for use in lists. I also tend to use seperate POCOs for saving and updating.
While it makes sense to standardize why POCOs are designed the way they are (e.g: they are all driven by the domain model, and there's only one POCO per entity) - the truth is that you'll have different motivations from different directions; my advice is to give in to this otherwise you'll end up with a system that is not flexible, easy to maintain or performant.
Using Interfaces
This is a more 'pure' approach. Rather than have your application pass concrete POCOs around use interfaces instead. Then when you build implement a POCO it can implement as many of those interfaces as you like. For example:
Bonus Point
You haven't asked for this (at least not directly) but I wouldn't tie my BL to EF - in fact I wouldn't tie it to the Data Access Layer at all. If you do, whatever wants to use your BL will be tied to the EF as well. You might want to consider Dependency Inversion.