I think the simplest approach would be to split your query and projection parts.
Query will be run by EF on database side, and retrieve all the fields.
Then you do your projection in-memory, and inject the property based on user's choice (the user is required to pick an existing property from a list).
One important thing to remember in an EF query, is that when you call ToList()
, you will perform the actual database query. Then all the further statements will be performed in memory.
// This will perform an EF query, filtered by the where predicate
var reportEntities = yourContext.YourEntityModelDbSet
// save resources on EF context if you don't need to update entities later
.AsNoTracking()
// Filter as much as you can in this predicate, for it will
// be translated into SQL by EF
.Where(x => x.Date > StartDate && x.Date <= EndDate)
// Calling ToList will retrieve all entites matching the where predicate
// including all their fields (take care of data size)
.ToList();
// Then, use reflection to retrieve the data
// according to user's choice
var userChoice = GetUserInput(); // will return the property name as a string
var report = reportEntities
.Select(x => new ReadTime
{
Date = x.Date,
// Using reflection to get the value of a property
// Given its name.
Kody5 = x.GetType().GetProperty(userChoice)?.GetValue(x, null)
})
.ToList();
The ?.
operator swallows any exception due to a non-existing
property choice. It guarantees you won't get a runtime exception, but
you'll never know if the property choice is wrong.
If the data volume is an issue (and it might, since you told you have like a hundred fields), perform a first Select()
before the ToList()
, where you will project strictly just the fields you will need, in any case.