1

列名が事前に知られていないエンティティの個別のプロパティ値を選択することは可能ですか - クライアントからの文字列としてメソッドによって受信されます。

フィルタリングの目的で、フィールド名をキーとして含むブラウザーからサーバーへの HTTP POST Ajax 要求を作成したいと考えています。これはサーバーで文字列として利用できます。

ViewModel と Entity Framework で使用される POCO クラスの違いを手動でマッピングする必要があることはわかっていますが、たとえばリフレクションを使用して、厳密に型指定されたプロパティを使用せずに Entity フレームワーク クエリを作成することは可能ですか。

おそらく、データがコントローラーによって決定された場所にこれを実装して、エンティティークラスをタイプとしてベースリポジトリーのジェネリックメソッドを呼び出すことを試みるでしょう。これは可能ですか、それとも可能なフィールドごとにメソッドを構築する必要がありますか?

同様に、これを実行しようとするか、代わりにフィールドをパラメーターとして使用して ADO.NET SQL コマンドを作成する必要がありますか (ViewModel から SQL 列名へのマッピング)。

4

2 に答える 2

6

最近、同様の回答を見たと確信していますが、見つかりません...

エンティティのタイプと選択するプロパティのタイプがわかっている場合、これは非常に簡単です。

public IQueryable<TProperty> SelectProperty<TEntity, TProperty>(DbContext context, string propertyName)
    where TEntity : class
{
    var parameter = Expression.Parameter(typeof(TEntity));
    var body = Expression.Property(parameter, propertyName);
    var lambda = Expression.Lambda<Func<TEntity, TProperty>>(body, parameter);
    var result = context.Set<TEntity>().Select (lambda).Distinct();

    return result;
}

プロパティのタイプを予測できない場合、式の作成はより困難になります。

public IQueryable SelectProperty<TEntity>(DbContext context, string propertyName)
    where TEntity : class
{
    var entities = context.Set<TEntity>();
    var query = entities.AsQueryable();
    var parameter = Expression.Parameter(typeof(TEntity), "instance");
    var propertyAccess = Expression.Property(parameter, propertyName);
    var projection = Expression.Lambda(propertyAccess, parameter);

    var selectExpression = Expression.Call(
        typeof(Queryable).GetMethods()
                         .First (x => x.Name == "Select")
                         .MakeGenericMethod(new[]{ typeof(TEntity), propertyAccess.Type }),
        query.Expression,
        projection);

    var distinctExpression = Expression.Call(
        typeof(Queryable).GetMethods()
                         .First (x => x.Name == "Distinct")
                         .MakeGenericMethod(new[]{ propertyAccess.Type }),
        selectExpression);

    var result = query.Provider.CreateQuery(distinctExpression);

    return result;
}
于 2013-09-09T21:57:09.813 に答える
0

これを行うには、Dyanmic Linq (nuget パッケージ: System.Linq.Dynamic) を使用できます。また、ここにある拡張メソッドも使用できます

サンプルコード:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace dlinq1
{
    class Thing
    {
        public int ID { get; set; }
    }
    class Program
    {
        static void Main(string[] args)
        {
            var things = new List<Thing>();
            for(int x=0;x<10;x++)
            {
                things.Add(new Thing{ID=x%2}); //0,1,0,1,0,1,0,1,0,1
            }
            var result = things.AsQueryable().Select("ID").Distinct();
            foreach (var r in result)
            {
                Console.WriteLine(r);
            }
            Console.ReadLine(); //produces 0, 1
        }
    }

    public static class DynamicQueryableExtras
    {
        public static IQueryable Distinct(this IQueryable q)
        {
            var call = Expression.Call(typeof(Queryable),
                                       "Distinct",
                                       new Type[] { q.ElementType },
                                       q.Expression);
            return q.Provider.CreateQuery(call);
        }
    }
}

基本的に、拡張機能は、Distinct を呼び出す直前の前の式以降、クエリ可能な状態がどのような状態でも機能します。

于 2013-09-09T22:35:47.050 に答える