2017-08-02 97 views
1

我正在尋找一種方法來獲取不同值的列表,我的表的一列。我需要制定一個可重用的方法。從實體框架中選擇具有動態列名稱的不同列

這是我試過到目前爲止,但它不工作:

IEnumerable<string> GetDistinctValues<T>(string columnName) 
{ 
    T.Select(m => m.ColumnName).Distinct().ToList(); 
} 

所需的解決方案應該是EF對象的擴展方法。

我試過這個帖子Dynamically select columns in runtime using entity framework,但它只適用於單個記錄而不是列表。

+0

的可能的複製[使用實體框架在運行時動態地選擇列] (https://stackoverflow.com/questions/21084916/dynamically-select-columns-in-runtime-using-entity-framework) –

+0

https://stackoverflow.com/a/31055926/3082296 – adiga

+0

任何你不做的原因選擇的參數作爲你的方法的參數?例如:IEnumerable GetDistinctValues (Func selector){T.Select(selector).Distinct()。ToList(); }'' –

回答

2

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"); 
+0

好,但是如果我沒有x.Name。我有列名作爲字符串「名稱」。 –

+0

你事先知道'TResult'的泛型參數是什麼嗎? –

+0

不,呼叫從其餘的WebService到達,所以我不知道類型的屬性。我需要推斷裏面的功能。我試過personQuery.GetDistinctValuesForProperty(x => x.GetType()。GetProperties()。其中​​(a => a.Name == ColumnName));但不能工作 –

0

最後我找到了解決方案。我需要包含對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由於鑄造問題

相關問題