Question

I am retrieving data from the database (with Entity Framework) using DTOs:

IQueryable<User> users = repository.ListFiltered<User>(n => n.Active);

var usersDTO = from user in users
               select new UserAccountDTO{
                   UserId = user.Id,
                   UserName = user.Name,
                   InstitutionName = user.Institution.Name,
                   InstitutionCountry = user.Institution.Country.Name
               };

I'm doing this because the user entity, and the institution entity, have a lot of data i don't need right now, so i don't want to retrieve it from the database.

But the problem is that i don't like the code, i would like to split the code and concatenate the selects, is there anyway to do this?

I'd like to arrive to something like:

users.LoadUserData().LoadInstitutionData();

What do you say? is it possible?

Was it helpful?

Solution

The problem is what LoadUserData() and LoadInstitutionData() should look like. Let's say that the end product of this method chain should be an IEnumerable<UserAccountDTO>. The last method in fluent syntax always determines the output. So LoadInstitutionData() should return the required IEnumerable. Clear.

But what about the input? I see two alternatives:

  • The input is IEnumerable<User> (or IQueryable<User>). OK, that would mean that LoadInstitutionData() can't do anything else than the code you already have. And that's not a solution, because you don't like the code. Moreover, the method requires that user.Institution and the Country must be loaded or lazy loadable, which is hard to express in any form of code contract.

  • The input is IEnumerable<UserAccountDTO> in which LoadUserData has set the direct user properties and that LoadInstitutionData should replenish with Institution data. Now the question is: how should LoadInstitutionData do that? Anyhow, what was done in one query now will take at least two queries, maybe even 1 + n.

More complex alternatives could consist of passing and composing expressions, but surely you'll be jumping from the frying pan into the fire, reinventing LINQ's extension methods, or AutoMapper, or...

Wait, AutoMapper.

Did you know that AutoMapper could do this for you in a way that may appeal to you?

All you need is a class

class UserAccountDTO
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string InstitutionName { get; set; }
    public string InstitutionCountryName { get; set; } // Notice the Name part!
};

A mapping

AutoMapper.Mapper.CreateMap<User, UserAccountDTO>();

A using:

using AutoMapper.QueryableExtensions;

And a concise syntax:

var usersDTO = users.Project().To<UserAccountDTO>();

(And AutoMapper from NuGet, of course).

Automapper will resolve a property like InstitutionCountryName as user.Institution.Country.Name and the result of the projection is one expression that is translated into one SQL statement with joins and all. That's code I do like.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top