Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Suggestions on how to map from Domain (ORM) objects to Data Transfer Objects (DTO)

The current system that I am working on makes use of Castle Activerecord to provide ORM (Object Relational Mapping) between the Domain objects and the database. This is all well and good and at most times actually works well!

The problem comes about with Castle Activerecords support for asynchronous execution, well, more specifically the SessionScope that manages the session that objects belong to. Long story short, bad stuff happens!

We are therefore looking for a way to easily convert (think automagically) from the Domain objects (who know that a DB exists and care) to the DTO object (who know nothing about the DB and care not for sessions, mapping attributes or all thing ORM).

Does anyone have suggestions on doing this. For the start I am looking for a basic One to One mapping of object. Domain object Person will be mapped to say PersonDTO. I do not want to do this manually since it is a waste.

Obviously reflection comes to mind, but I am hoping with some of the better IT knowledge floating around this site that "cooler" will be suggested.

Oh, I am working in C#, the ORM objects as said before a mapped with Castle ActiveRecord.


Example code:

By @ajmastrean's request I have linked to an example that I have (badly) mocked together. The example has a capture form, capture form controller, domain objects, activerecord repository and an async helper. It is slightly big (3MB) because I included the ActiveRecored dll's needed to get it running. You will need to create a database called ActiveRecordAsync on your local machine or just change the .config file.

Basic details of example:

The Capture Form

The capture form has a reference to the contoller

private CompanyCaptureController MyController { get; set; } 

On initialise of the form it calls MyController.Load() private void InitForm () { MyController = new CompanyCaptureController(this); MyController.Load(); } This will return back to a method called LoadComplete()

public void LoadCompleted (Company loadCompany)
{
    _context.Post(delegate
    {
         CurrentItem = loadCompany;
         bindingSource.DataSource = CurrentItem;
         bindingSource.ResetCurrentItem();
         //TOTO: This line will thow the exception since the session scope used to fetch loadCompany is now gone.
         grdEmployees.DataSource = loadCompany.Employees;
         }, null);
    }
}

this is where the "bad stuff" occurs, since we are using the child list of Company that is set as Lazy load.

The Controller

The controller has a Load method that was called from the form, it then calls the Asyc helper to asynchronously call the LoadCompany method and then return to the Capture form's LoadComplete method.

public void Load ()
{
    new AsyncListLoad<Company>().BeginLoad(LoadCompany, Form.LoadCompleted);
}

The LoadCompany() method simply makes use of the Repository to find a know company.

public Company LoadCompany()
{
    return ActiveRecordRepository<Company>.Find(Setup.company.Identifier);
}

The rest of the example is rather generic, it has two domain classes which inherit from a base class, a setup file to instert some data and the repository to provide the ActiveRecordMediator abilities.

like image 884
FryHard Avatar asked Sep 03 '08 13:09

FryHard


People also ask

How do you implement DTO?

In order to implement DTO, let's create a Spring Boot application that exposes REST API. By using that Spring Boot application, we can retrieve the user locations from an H2 database. For implementing that application, we should have knowledge of how to integrate the H2 database with Spring Boot.

What is Mapper 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.

What is the difference between DTO and Domain object?

If using anemic data model (i.e. your domain objects don't have any logic), DTO and domain object can be the same object. No. Domain objects have no specific relation to any persistence. In simple words, they are parts to ensure the business logic required to run the application.

Can we use DTO in repository?

Short answer: No. Long answer: repository is responsible for turning persisted data back to entities (models) and vice versa. Model is a business Model representing a business entity.


1 Answers

I solved a problem very similar to this where I copied the data out of a lot of older web service contracts into WCF data contracts. I created a number of methods that had signatures like this:

public static T ChangeType<S, T>(this S source) where T : class, new()

The first time this method (or any of the other overloads) executes for two types, it looks at the properties of each type, and decides which ones exist in both based on name and type. It takes this 'member intersection' and uses the DynamicMethod class to emil the IL to copy the source type to the target type, then it caches the resulting delegate in a threadsafe static dictionary.

Once the delegate is created, it's obscenely fast and I have provided other overloads to pass in a delegate to copy over properties that don't match the intersection criteria:

public static T ChangeType<S, T>(this S source, Action<S, T> additionalOperations) where T : class, new()

... so you could do this for your Person to PersonDTO example:

Person p = new Person( /* set whatever */);
PersonDTO = p.ChangeType<Person, PersonDTO>();

And any properties on both Person and PersonDTO (again, that have the same name and type) would be copied by a runtime emitted method and any subsequent calls would not have to be emitted, but would reuse the same emitted code for those types in that order (i.e. copying PersonDTO to Person would also incur a hit to emit the code).

It's too much code to post, but if you are interested I will make the effort to upload a sample to SkyDrive and post the link here.

Richard

like image 186
ZeroBugBounce Avatar answered Oct 03 '22 16:10

ZeroBugBounce