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>
(orIQueryable<User>
). OK, that would mean thatLoadInstitutionData()
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 thatuser.Institution
and theCountry
must be loaded or lazy loadable, which is hard to express in any form of code contract.The input is
IEnumerable<UserAccountDTO>
in whichLoadUserData
has set the directuser
properties and thatLoadInstitutionData
should replenish withInstitution
data. Now the question is: how shouldLoadInstitutionData
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.