Mapping instances of one type to such of another is a widely used technique. A great way to avoid writing the tedious and repetitive code for such functionality in your Telerik Data Access application is to use AutoMapper. It is a powerful and easy to use tool for object to object mapping. Here we will share with you three tips that would help you take advantage of this combination.

For our examples we will use the CarDTO and CategoryDTO classes:

public class CarDTO
{
    public int CarID { get; set; }
    public string Make { get; set; }
    public string Model { get; set; }
    public string TagNumber { get; set; }
    public CategoryDTO Category { get; set; }
}

public class CategoryDTO
{
    public int CategoryID { get; set; }
    public string CategoryName { get; set; }
}

They would be the DTOs for the Car and Category persistent classes respectively:


1. Using Fetch Strategy when Mapping Entities with their Navigation Properties to DTOs

You can easily employ AutoMapper in order to map a graph of your persistent entities to DTOs. All you need to do is create the mapping configuration between the respective types and call the Map method for the entity or entities you wish to map to DTOs:

using (EntitiesModel context = new EntitiesModel())
{
    Mapper.CreateMap<Car, CarDTO>();
    Mapper.CreateMap<Category, CategoryDTO>();

    var carDtos = Mapper.Map<IList<CarDTO>>(context.Cars.ToList());
}

Short and simple, however there is a detail that can be easily missed - navigation properties are lazy loaded. As AutoMapper can map graphs of objects, this means that the Map method will make additional calls to the database in order to retrieve the Categories related to the Cars. The result is behavior akin to the N+1 problem and a possible negative effect on the performance of your application.

To prevent such undesired behavior you can define and use a FetchStrategy which specifies which navigation properties must be loaded together with the entity:

using (EntitiesModel context = new EntitiesModel())
{
    Mapper.CreateMap<Car, CarDTO>();
    Mapper.CreateMap<Category, CategoryDTO>();

    FetchStrategy loadCarWithCategory = new FetchStrategy();
    loadCarWithCategory.LoadWith<Car>(car => car.Category);
    context.FetchStrategy = loadCarWithCategory;

    var carDtos = Mapper.Map<IList<CarDTO>>(context.Cars.ToList());
}

This way the Categories will be loaded in the same call to the database in which the Cars are retrieved in memory. To read more about FetchStrategies, check out our documentation about them.

2. Avoid Using AutoMapper IQueryable Extensions with Telerik Data Access

If you are using AutoMapper you are probably familiar with its IQueryable extension methods. They allow you to directly retrieve only the required information and project it into a DTO directly in your LINQ query:

using (EntitiesModel context = new EntitiesModel())
{
    Mapper.CreateMap<Car, CarDTO>();
    Mapper.CreateMap<Category, CategoryDTO>();

    IList<CategoryDTO> categories = this.context.Categories.Project().To<CategoryDTO>().ToList();
}

While this functionality allows you avoid writing explicit projection in to your LINQ query it has the same fatal flaw as doing so - it prevents the query result from being cached. 

Since this can have a strong negative impact on the performance even though only minimal amount of data is retrieved, we advise you not to use AutoMapper projection in LINQ queries. Instead we recommend you map the instances of your persistent types after they have been completely retrieved in memory using the Map method of AutoMapper.

3. Converting DTOs Back to Entities

Eventually in your application you would need to convert the used DTOs back to entities. Those entities may be new and need to be persisted in the database or contain updates for already persisted objects. The entities received from DTOs however are not being managed by an OpenAccessContext instance. While you can use the Add method to persist the new entities, you would not be able to handle with it entities which carry an update for an already persisted object.

Telerik Data Access provides you a way to handle both of those scenarios using the same approach – the AttachCopy method:

using (EntitiesModel context = new EntitiesModel())
{
    Mapper.CreateMap<Category, CategoryDTO>().ReverseMap();

    CategoryDTO sourceCategoryDto = new CategoryDTO()
    {
        CategoryID = 1,
        CategoryName = "Space Car"
    };

    Category targetCategoryEntity = Mapper.Map<Category>(sourceCategoryDto);

    Category attachedCar = null;
    if (targetCategoryEntity != null)
    {
        attachedCar = context.AttachCopy(targetCategoryEntity);
        context.SaveChanges();
    }
}

The context object will automatically determine whether the attached entity is new or if it is an already existing one. In case the attached entity is new it would be persisted in the database when SaveChanges is called, if it is an already existing object it will use it to push possible updates to the database. In case you are interested in learning more about the AttachCopy method, you can do so here.

With these simple tips in mind AutoMapper would be easy to integrate with Telerik Data Access and could greatly ease the development of your application. Do not forget to regularly check out our blog - next week we will present you our powerful bulk select capabilities for loading multiple objects based on a list of values with minimum amount of database calls.

Download Data Access
About the Author

Kristian Nikolov

Kristian Nikolov is Support Officer.

Comments

Comments are disabled in preview mode.