Reputation: 893
This is a follow-up for my question from here.
First of all, I am not using DDD in my project.
I have a WCF service with 3 layers:
The WCF service needs to return DTO objects, and I am having trouble figuring out the best place to put the 'Translator' class that translates my POCO entities to DTOs.
I had 2 options for this:
.
.
METHOD A
Have the business logic methods return entities to the service layer, and the service layer has a translator class in it that translates entities to DTOs.
PROS:
CONS:
.
.
METHOD B
Have the 'Translator' class that translates from entity objects to DTOs placed in the 'business logic layer' itself. In this mechanism - the BL methods return DTOs already.
PROS:
CONS:
.
Can anyone tell me where the right place is to perform the 'Entity ==> DTO' conversion ?
.
[Update - Added Example]
Business Logic layer has a manager class called UserManager that has a BL method like this:
public UserTasksDto GetUserInfoWithTasks(Guid userId)
{
if (userId == Guid.Empty)
throw new ArgumentException("User ID cannot be empty");
using (IMyDBEntities entities = _contextFactory.GetContext())
{
// Get POCO Object from DbContext
User user = entities.Users.Find(userId);
if (user == null)
throw new EntityNotFoundException("User was not found in the database");
if (user.Tasks.Count() == 0)
throw new Exception("User does not have any tasks !");
// Call 'Translator' static method to translate POCO to DTO
Translator.TranslateUserToUserTasksDto(user);
}
}
As you can see above - the BL method calls a 'translator' method to turn POCO to DTO. This is done inside the 'entities' context, so that the translator can still access the user's 'Tasks' children.
Here is what the 'Translator' method looks like:
class Translator
{
public static UserTasksDto TranslateUserToUserTasksDto ( User userPoco )
{
UserTasksDto dto = new UserTasksDto
{
UserId = userPoco.Id,
Username = userPoco.Username,
CreationDate = userPoco.CreationDate,
// Accessing a related entity, this is why this 'translate' method
// needs to be called inside the DbContext, otherwise it will except
// (or we load all related entities using 'Include' just for the 'Count' purpose)
Supervisor = userPoco.Supervisor.Username,
NumOfTasks = userPoco.Tasks.Count(),
FirstTaskDate = userPoco.Tasks.OrderBy(task => task.Date).Take(1),
}
return dto;
}
}
As you can see above - the 'Translate' method 'builds' a 'UserTasksDto' from a 'User' POCO object. This is done by mapping some fields from the 'User' object and it's related entities to the DTO. If this method was not inside the BL method's ObjectContext - I would get an exception saying I am trying to access entities without a context.
I hope my problem now is more clear...
Upvotes: 4
Views: 1926
Reputation: 762
Though question,
If you need your service layer to be independent of the BL/DAL data entities, then, in my opinion you have to have a new abstraction layer (dll assembly) for independent models.
Your BL and/or DAL now will not return Entities, but rather Model objects from this new assembly.
Your Service layer will not require a reference to the DAL for the entities, but a reference to the new Models assembly.
This is a similar pattern to the view models.
Now the service layer's job is to transform the models to DTO if it chooses to do so.
PROS: Will release you of BL/DAL dependency
CONS: Models abstraction layer will look as if redundent
EDIT:
Oh, I did not mean to return DTOs from the business layer. What I meant was to return independent models from the business logic so that they will really be independent from all the layers, and whichever layer that works with them afterwards can use them or transform them to whatever form needed.
For example the service layer may include a model to DTO translater, a presentation layer may transform them into view models, a repository may choose to transform them to XML .... and so on and so forth. Now each layer will have its own Model to X transformer, BL will only have single responsibility, and all layers will be independent from the DAL entities.
N.B. Some layers may choose to use them directly, this I believe was your concern, and yes if they do so they will act as if BL returned a DTO/VM, but this was not my intention.
Hope this clears up things now...
UPDATE:
Think of it that you are a developer who will not write any layer other than the BL.
Would you return the entities of DAL. NO.
Will you have any notion of how will your library be used, and what layers will use it. NO.
You will create a new abstraction on top of the DAL entities and return these to WHICHEVER layer that will use your library.
So if developer X comes along and uses your library to create an ACME WCF service, I am pretty sure X will not use your model object as his DTO, rather X will create DTOs using your models as a start.
Developer Y comes along and uses your library to create an ACME ASP.NET MVC 3 application, I am pretty sure Y will not use your model object as his VMs (View Models), rather Y will create VMs using your models as a start.
Upvotes: 2
Reputation: 12904
There probably is no right place, but the most logical place would be with your Business Logic.
Upvotes: 0