I am looking for a solution to select a single column based on the column name. The type of columns I want to select is always string. Like so:
_dbContext.MyModel.Select("Name")...
I wanted to create a extension method:
_dbContext.MyModel.SelectFromString("Name")
It should allow nested selects, like:
_dbContext.MyModel.SelectFromString("Child.Name")
Extension method:
public static IQueryable<T> SelectFromString<T>(this IQueryable<T> query, string column)
{
var parameter = Expression.Parameter(typeof(T));
var property = Expression.Property(parameter, column);
//...
return query.Select(lambda);
}
Not sure how to create the lambda. Any ideas?
CodePudding user response:
The following method projects any property to string and returns IQueryable<string>
. Nested properties also supported.
public static class QueryableExtensions
{
public static IQueryable<string> SelectFromString<T>(this IQueryable<T> query, string column)
{
var parameter = Expression.Parameter(typeof(T), "e");
var property = MakePropPath(parameter, column);
if (property.Type != typeof(string))
{
if (property.Type != typeof(object))
property = Expression.Convert(property, typeof(object));
property = Expression.Call(_toStringMethod, property);
}
var lambda = Expression.Lambda<Func<T, string>>(property, parameter);
return query.Select(lambda);
}
private static Expression MakePropPath(Expression objExpression, string path)
{
return path.Split('.').Aggregate(objExpression, Expression.PropertyOrField);
}
private static MethodInfo _toStringMethod = typeof(Convert).GetMethods()
.Single(m =>
m.Name == nameof(Convert.ToString) && m.GetParameters().Length == 1 &&
m.GetParameters()[0].ParameterType == typeof(object)
);
}