I have a generic repository that uses generic expressions for returning data from Entity Framework Core.
public async Task<T2> GetFieldsAsync<T2>(Expression<Func<T, T2>> expression)
{
return await context.Set<T>()
.Select(expression)
.FirstOrDefaultAsync();
}
Now if I want to select specific fields, at compile time I can write the following statement:
var test = await _repositoryBase.GetFieldsAsync(x => new { x.Id, x.Name });
I want to be able to do above at run time instead. I can create an expression at run time that returns a single parameter as follows:
var expression = Expression.Parameter(typeof(Ingredient), "ingr");
var param1 = Expression.Property(expression, "Id");
var lambda = Expression.Lambda<Func<Ingredient, Guid>>(param1, expression);
var test = await _repositoryBase.GetFieldsAsync(lambda);
The above lambda only returns a single property from the Ingredient class. Is it possible to create a run time lambda that returns an anonymous object using expression trees? I.e.
x => new { x.Id, x.Name }
Note that users might request different fields (e.g. Name, Description, DateCreated, etc.) so need to dynamically create the lambda expression.
I know I can use https://github.com/StefH/System.Linq.Dynamic.Core to pass in strings to select statements via its built-in IQueryable extension methods. I am wondering if there is a way to dynamically select specific fields at run time via a list of fields passed in by the user.
Currently, my approach is to get all properties of the class from the database, and use an ExpandoObject to only select the fields that user requests. The issue here is that although it works, I am returning more data from the database than is required. I'd like to avoid this by only selecting the required data.
//user did not provide any fields so include all fields
if (string.IsNullOrEmpty(field))
{
myPropertyInfoList.AddRange(typeProperties);
}
else
{
foreach (var item in fields)
{
myPropertyInfoList.Add(type.GetProperty(item, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance));
}
var expandoObj = (IDictionary<string, object>)new ExpandoObject();
foreach (var item in myPropertyInfoList)
{
expandoObj.Add(item.Name, item.GetValue(ingrView));
}