2017-08-02 14 views
1

私のテーブルの1つの列に対して異なる値のリストを取得する方法を探しています。私は再利用可能な方法を作る必要があります。動的な列名を使用してEntity Frameworkから別の列を選択してください

これは私がこれまで試したものですが、それは動作しません:

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

所望の解は、EFのオブジェクトに対する拡張メソッドでなければなりません。

私はこのポストDynamically select columns in runtime using entity frameworkを試しましたが、リストではなく単一のレコードに対してのみ機能します。キャッシュを経由して、私は拡張子を経由して、それを処理し、反射性能を改善する

+0

可能な複製をIEnumerableを対の配列を使用する必要が

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]; } 

として呼び出します(https://stackoverflow.com/questions/21084916/dynamically-select-columns-in-runtime-using-entity-framework) –

+0

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

+0

あなたのメソッドの引数としてselectの引数?次のようなものがあります。 '' IEnumerable GetDistinctValues (Func セレクタ){T.Select(セレクタ).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から着信します。したがって、プロパティのタイプはわかりません。私は内部の機能を推測する必要があります。私はtryQuery.GetDistinctValuesForProperty(x => x.GetType()。GetProperties()。ここで(a => a.Name == ColumnName));しかし仕事はできません –

0

最後に解決策が見つかりました。 System.Linq.Dynamicへの参照(ナゲットでダウンロード)を含める必要があり、参照列にStringを受け入れる「選択」メソッドを使用します。

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(); 
    } 

と私は日時型の場合に起因するキャストの問題に[エンティティフレームワークを使用して、ランタイムで動的に選択列]の

関連する問題