可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I've seen a lot of questions related to mapping DTOs to Domain Objects, but I didn't feel they answered my question. I've used many methods before and have my own opinions but I'm looking for something a little more concrete.
The Situation:
We have many domain objects. We are using a CSLA model so our domain objects can be pretty complex and they contain their own data access. You do not want to pass these around on the wire. We are going to be writing some new services that will return data in a number of formats (.Net, JSON, etc.). For this (and other reasons) we are also creating a lean, data transfer object to pass around on the wire.
My question is how should the DTO and Domain object be connected?
My first reaction is to use a Fowler, DTO pattern-type solution. I've seen this done many times and it feels right to me. The domain object contains no reference to the DTO. An outside entity (a "mapper" or "assembler") is called to create a DTO from a Domain Object. Normally there is an ORM on the domain object side. The downside of this is that the "mapper" tends to get extremely complex for any real situation and can be very fragile.
Another idea put forth is for the Domain Object to "contain" the DTO, since it's just a lean data object. The Domain Object properties would internally reference the DTO properties and could just return the DTO if asked for. I can see no problems with this but it feels wrong. I have seen some articles where people using NHibernate appeared to use this method.
Are there other ways? Is one of the ways above worth using? If so or if not, why?
Thanks for any insight in advance.
回答1:
A benefit of having a mapper that sits between your domain and your DTO is not as appearent when you are only supporting a single mapping, but as the number of mappings increases, having that code isolated from the domain helps keep the domain simpler and leaner. You won't be cluttering your domain with a lot of extra weight.
Personally, I try and keep the mapping out of my domain entities and put the responsibility in what I call "Manager / Service layer". This is a layer that sits between the application and the respository(ies), and provides business logic such as workflow coordination (If you modify A, you might have to also modify B so service A will work with Service B).
If I had a lot of possible ending formats, I might look at creating a plugable formatter that could use the Visitor pattern, for example to transform my entities, but I've not found a need yet for anything this complex.
回答2:
You could use an automapper such as the one written by Jimmy Bogard which has no connection between the objects and relies on naming conventions being adhered to.
回答3:
We use T4 templates to create the mapping classes.
Pro's - human readable code available at compile time, faster than a runtime mapper. 100% control over the code (can use partial methods/template pattern to extend functionality on an ad-hoc basis)
Con's - excluding certain properties, collections of domain objects etc., learning T4 syntax.
回答4:
How do you see to implement a constructor inside the DTO class that takes as a parameter a domain object?
Say... Something like this
class DTO {
// attributes
public DTO (DomainObject domainObject) {
this.prop = domainObject.getProp();
}
// methods
}
回答5:
Another possible solution: http://glue.codeplex.com.
Features:
- Bidirectional mapping
- Automatic mapping
- Mapping between different types
- Nested mapping and Flattening
- Lists and Arrays
- Verification of relations
- Testing the mapping
- Properties, Fields and Methods
回答6:
You can also try Otis, an Object-to-object mapper. Concepts are similar to NHibernate mapping (attribute or XML).
http://code.google.com/p/otis-lib/wiki/GettingStarted
回答7:
I can suggest a tool I created and is open source hosted at CodePlex: EntitiesToDTOs.
Mapping from DTO to Entity and vice-versa is implemented by extension methods, these compose the Assembler side of each end.
You end with code like:
Foo entity = new Foo();
FooDTO dto = entity.ToDTO();
entity = dto.ToEntity();
List<Foo> entityList = new List<Foo>();
List<FooDTO> dtoList = entityList.ToDTOs();
entityList = dtoList.ToEntities();
回答8:
Why not we can do like this?
class UserDTO {
}
class AdminDTO {
}
class DomainObject {
// attributes
public DomainObject(DTO dto) {
this.dto = dto;
}
// methods
public function isActive() {
return (this.dto.getStatus() == 'ACTIVE')
}
public function isModeratorAdmin() {
return (this.dto.getAdminRole() == 'moderator')
}
}
userdto = new UserDTO();
userdto.setStatus('ACTIVE');
obj = new DomainObject(userdto)
if(obj.isActive()) {
//print active
}
admindto = new AdminDTO();
admindto.setAdminRole('moderator');
obj = new DomainObject(admindto)
if(obj.isModeratorAdmin()) {
//print some thing
}
@FrederikPrijck (or) someone: Please suggest. In the above example DomainObject is depends on DTO. By this way i can avoid the code to do mapping the dto <--> domainobject.
or DomainObject class can extends the DTO class?
回答9:
Another option would be to use ModelProjector. It supports all possible scenarios and is very easy to use with minimal footprint.
回答10:
We can use Factory, Memento, and Builder pattern for that. Factory hide the details on how to create instance of domain model from DTO. Memento will take care the serialization/deserialization of the domain model to/from DTO and can even access private members. The Builder will allows mapping from DTO to domain with fluent interface.