As we all know most apps have a data access layer, often using repository classes. Typically we want the repository to operate with strongly typed objects, e.g.
interface IUserRespository
{
User GetUserByID(int id);
void AddUser(User u);
... and so on
}
However, sometimes we want to make a more complex query on a DB, that involves grouping and aggregation. For instance we want fetch a total value of all orders of all users (the result set will have only two columns: UserName and TotalAmount). Now my question: what would the repository method look like? There are dozens of examples on the internet of LINQ to entities how to make a query with sum and group by, but all these examples return anonymous types. So, how can our repository return the result of such query? The other common answer is: wrap it in a class. So the method could look like this:
interface IUserRepository
{
UserOrderTotal[] GetOrderTotalsForAllUsers();
}
UserOrderTotal would have to be a small class with the two properties returned by the query: UserName and TotalAmount. This class would be defined somewhere in one of our .cs files. Is this really the only solution? It looks very bad because it introduces a new 'temporary' model somewhere outside the main entities model (edmx). Ideally I'd like to enrich my User model with a new field, called TotalAmount, that would only be populated in this query, so the interface could look like this:
interface IUserRepository
{
User[] GetOrderTotalsForAllUsers();
}
And it would return User entities with all fields set to default, except the Name and TotalAmount. The problem that I have is that I cannot compile a model with field that is not mapped to a database column. I'm getting error Error 3004: Problem in mapping fragments starting at line 2226:No mapping specified for properties User.TotalAmount in Set User.An Entity with Key (PK) will not round-trip when: Entity is type [FPSoMeterModel.User]
Am I doing it wrong? Is this problem trivial, or maybe I'm asking wrong questions? Making a wrapper class for each query (!) that involves aggregation seems a bit ridiculous. It seems that the whole LINQ stuff encourage people NOT to use a multi-tier architecture, but to build queries in the same layer where the data is rendered... How do you guys deal with this, do you use "repository" classes with LINQ, if yes - how do you return complex query results?