views:

691

answers:

3

So I have a DAO, DTO, and BO. The following code is the result:

// Instantiate a new user repository.
UserRepository rep = new UserRepository();

// Retrieve user by ID (returns DTO) and convert to business object.
User user = rep.GetById(32).ToBusiness<User>();

// Perform business logic.
user.ResetPassword();
user.OtherBusinessLogic("test");
user.FirstName = "Bob";

// Convert business object back to a DTO to save to the database.
rep.Save(user.ToDataTransfer<Data.DTO.User>());

So I am trying to separate concerns, but I want to get rid of the "converts" in this code. The "converts" are actually located in the business logic layer (DTO layer knows nothing of the business logic layer) as an extension object. The DTO itself obviously only stores data and has no business logic what-so-ever. The UserRepository calls the DAO and at the end of GetById uses AutoMapper to map from the DAO to DTO. The "converts" (ToBusiness and ToDataTransfer) do exactly as they say.

A colleague of mine thought I may have to have a Business Repository, but thought it might be a bit clunky. Any thoughts?

Thanks.

+1  A: 

This is the first time I see a DTO being transformed into a BO, I normally send a DTO to be consumed by a BO class or method. When the BO is done and wants to save modifications to the DTO it sends it to the DAL and have it persisted.

Otávio Décio
Thanks for your reply. Any sample code you could provide would be helpful.
Josh Barker
I agree with this. You should get back your Business Object and if you need to convert to a DTO then that conversion could take place with a tool such as AutoMapper.
Keith Rousseau
+4  A: 

My only source of confusion here is why the calls to ToBusiness<User>() and ToDataTransfer<Data.DTO.User>() are necessary.

The responsibility of the Repository is to handle data management. It should hide the implementation details (as well as the conversions between Business Objects and Data Objects).

A UserRepository should return a User without any casting needed.

The UserRepository should also be able to persist a User without casting.

The code would be much cleaner if all the casting was handled in the Repository and your code read as:

UserRepository rep = new UserRepository();

User user = rep.GetById(32);

// Do Work Here

rep.Save(user);
Justin Niessner
You're proposing not having a DTO object and skipping right to a Business Object?re: Cleaner code- I completely agree-- this is what I am trying to get at using those separation of concerns.
Josh Barker
Correct me if I'm wrong here Justin, but I don't think Justin is proposing not having a DTO, but rather is suggesting to hide it. The repository would call the conversion methods between DTO and BO so that while you are programming normal business functionality you would never have to see or know about the DTO.
rayd09
+1  A: 

I resolved this by creating a Business Service layer. This way I can access functionality through the Business Service layer which in turn uses the Repositories which query the DAL and returns DTOs. The DTOs serve their purpose by being populated by the DAL and help transfer the data to the business layer (converted to business objects).

So the diagram is as follows:

DAL -> Repository (returns DTO) -> Service (returns BO)

It works very well and I am able to put business logic in the Service layer which abstracts it from the Repository itself. Sample code:

// UserService uses UserRepository internally + any additional business logic.
var service = new UserService();
var user = service.GetById(32);

user.ResetPassword();
user.OtherBusinessLogic("test");
user.FirstName = "Bob";

service.Save(user);

Josh

Josh Barker