从实体框架中选择具有动态列名称的不同列
我正在寻找一种方法来获取不同值的列表,我的表的一列。我需要制定一个可重用的方法。从实体框架中选择具有动态列名称的不同列
这是我试过到目前为止,但它不工作:
IEnumerable<string> GetDistinctValues<T>(string columnName)
{
T.Select(m => m.ColumnName).Distinct().ToList();
}
所需的解决方案应该是EF对象的扩展方法。
我试过这个帖子Dynamically select columns in runtime using entity framework,但它只适用于单个记录而不是列表。
我Linq.Dynamic
看到的唯一的问题是,有没有更新,自2013年起,该项目是非常死
我将通过扩展处理它,并通过缓存提高反射性能(这里就不详述了)
扩展:
public static class QueryableExtensions
{
public static IReadOnlyCollection<TResult> GetDistinctValuesForProperty<T, TResult>(this IQueryable<T> query, Expression<Func<T, TResult>> propertyAccess)
{
return SelectDistinct(query, propertyAccess).ToList();
}
public static IReadOnlyCollection<object> GetDistinctValuesForProperty<TSource>(this IQueryable<TSource> query, string propertyName)
{
var unboundFuncType = typeof(Func<,>);
var unboundExprType = typeof(Expression<>);
var sourceType = typeof(TSource); // TSource
var resultType = typeof(TSource)
.GetProperty(propertyName)
.PropertyType; // TResult
// Func<TSource, TResult>
var funcType = unboundFuncType.MakeGenericType(new [] { sourceType, resultType });
// Expression<Func<TSource, TResult>>
var expressionType = unboundExprType.MakeGenericType(new [] { funcType });
// Instance of Expression<Func<TSource, TResult>>, for example x => x.Name
var propertyAccess = typeof(StringExtensions)
.GetMethod(nameof(StringExtensions.AsPropertyExpression), new[] { typeof(string) })
.MakeGenericMethod(new [] { sourceType, resultType })
.Invoke(null, new object[] { propertyName });
// SelectDistinct query transform
var selectDistinctMethod = typeof(QueryableExtensions)
.GetMethod(nameof(QueryableExtensions.SelectDistinct), BindingFlags.NonPublic | BindingFlags.Static)
.MakeGenericMethod(new [] { sourceType, resultType });
// IQueryable<TSource> ==> IQueryable<TResult>
var result = selectDistinctMethod.Invoke(null, new object[] { query, propertyAccess });
// Cast to object via IEnumerable and convert to list
return ((IEnumerable)result).Cast<object>().ToList();
}
private static IQueryable<TResult> SelectDistinct<TSource, TResult>(this IQueryable<TSource> query, Expression<Func<TSource, TResult>> propertyAccess)
{
return query.Select(propertyAccess).Distinct();
}
}
public static class StringExtensions
{
public static Expression<Func<T, TResult>> AsPropertyExpression<T, TResult>(this string propertyName)
{
var parameter = Expression.Parameter(typeof(T), "x");
var property = typeof(T).GetProperty(propertyName);
var body = Expression.MakeMemberAccess(parameter, property);
return Expression.Lambda<Func<T, TResult>>(body, parameter);
}
}
用法:
public class Person
{
public string Name { get; }
public int Age { get; }
public Person(string name, int age)
{
Name = name;
Age = age;
}
}
var people = new Person[]
{
new Person("John", 25), new Person("Peter", 25), new Person("Sean", 25),
new Person("John", 32), new Person("Peter", 32),
};
var query = people.AsQueryable();
var namePropertyExpression = "Name".AsPropertyExpression<Person, string>();
var agePropertyExpression = "Age".AsPropertyExpression<Person, int>();
// When you know the result type
var names1 = query.GetDistinctValuesForProperty(x => x.Name);
var ages1 = query.GetDistinctValuesForProperty(x => x.Age);
// When you know the result type, but you may want to reuse the property expression
var names2 = query.GetDistinctValuesForProperty(namePropertyExpression);
var ages2 = query.GetDistinctValuesForProperty(agePropertyExpression);
// When you just know the property name
var names3 = query.GetDistinctValuesForProperty("Name");
var ages3 = query.GetDistinctValuesForProperty("Age");
好,但是如果我没有x.Name。我有列名作为字符串“名称”。 –
你事先知道'TResult'的泛型参数是什么吗? –
不,呼叫从其余的WebService到达,所以我不知道类型的属性。我需要推断里面的功能。我试过personQuery.GetDistinctValuesForProperty(x => x.GetType()。GetProperties()。其中(a => a.Name == ColumnName));但不能工作 –
最后我找到了解决方案。我需要包含对System.Linq.Dynamic的引用(由nuget下载),并使用接受字符串引用列的“Select”方法。
using System.Linq.Dynamic;
public static async Task<IEnumerable<Object>> GetDistinctValuesForProperty<T>(this IQueryable<T> query, String PropertyName)
{
return await query.Select(PropertyName).Distinct().ToListAsync();
}
,并调用作为
String ColumnName = "DateTimeInsert";
DbSet<Log> oDbSet = _uow.DbContext.Set<Log>();
Array DistinctValues;
if (typeof(Log).GetProperty(ColumnName) != null)
{
DistinctValues = (await oDbSet.GetDistinctValuesForProperty(ColumnName)).ToArray();
}
else
{
DistinctValues = new object[0];
}
我需要在日期时间类型的情况下,使用阵列VS的IEnumerable由于铸造问题
的可能的复制[使用实体框架在运行时动态地选择列] (https://stackoverflow.com/questions/21084916/dynamically-select-columns-in-runtime-using-entity-framework) –
https://stackoverflow.com/a/31055926/3082296 – adiga
任何你不做的原因选择的参数作为你的方法的参数?例如:IEnumerable GetDistinctValues (Func selector){T.Select(selector).Distinct()。ToList(); }'' –