I have a webservice that allows the user to query a give subset of data from a database. I will only know which fields the user wants at runtime. It's quite easy to build a dynamic linq query to retrieve only the corresponding properties from the database for the fields in the object table itself, but how can I dynamically specify which fields I want to retrive in the related table ? Sounds confusing, let me explain with a sample.
So let's say I have a structure like:
class User {
public string Name {get; set;}
public List<Role> Roles {get; set;}
}
class Role {
public string RoleName {get; set;}
public string RoleDescription {get; set;}
}
So User and Role are the objects used by EF6 in my code first databse table generation.
Now I have webservice that wants to get the username and the name of the roles from the database. It will send a parameter like
var requestData = "{fields: {'Name', 'Roles.RoleName'}}"`;
What I would like to do is only retrieve the RoleName field from the Roles collection, knowing another client might ask the Roles.RoleDescription only so I need to dynamically create the query. Ideally I should be able to generate this at the Select level on an IQueryable object in order to avoid getting a huge number of data from the database and only using one field.
What I have tried so far:
Using System.Linq.Dynamic to retrieve the properties of the User table. Something like:
var dynamicFields = GetFieldsFromRequestData(requestData); // results in "Name, Roles"
var query = context.Set<User>().Select(dynamicFields);
query.Load();
Works like a charm. BUT will query all fields from the Roles collection. I don't seem to be able to only select the Roles.RoleName column from the Roles table using the same strategy, which is what I want.
var query = context.Set<User>().Select("Name, Roles.RoleName");
Does not work.
I also tried using Linq.Expressions which requires specifying the objects types:
class UserDTO {
public string Name {get; set;}
public List<RoleDTO> Roles {get; set;}
}
class RoleDTO {
public string RoleName {get; set;}
}
then using Linq.Expressions I generate
var generatedExpression = GetFieldsFromRequestDataLinq(requestData); //
results in an expression = (user => New UserDTO {Name = user.Name, Roles = user.Roles });
var query = context.Set<User>().Select(generatedExpression);
Works like a charm EF converts the objects in the Roles collection to RoleDTO objects.
BUT this implies knowing in advance which fields will be queried in the Roles collection since I defined the RoleDTO type. Which is not what I want since I don't know the list of queried fields.
So if someone has a nice way of solving this issue that would be awesome. I am open to AutoMapper solutions, to Newtonsoft JSON approaches, ...
Have been battling with this since 10 days ;-)