21

Company (文字列)、Fund (文字列)、State (文字列)、Value (double) の 4 つの列を持つ DataTable があるとします。

    table1.Rows.Add("Company 1","Fund 1","NY",100));
    table1.Rows.Add("Company 2","Fund 1","CA",200));
    table1.Rows.Add("Company 3","Fund 1","FL",300));
    table1.Rows.Add("Company 4","Fund 2","CA",400));
    table1.Rows.Add("Company 5","Fund 1","NY",500));
    table1.Rows.Add("Company 6","Fund 2","CA",600));
    table1.Rows.Add("Company 7","Fund 3","FL",700));

System.LINQ.Dynamic を使用して、Company、Fund、または State のいずれかでグループ化する動的クエリを作成し、最初の列として条件と合計 (値) としてグループを選択します。

string groupbyvalue="Fund";
var q1= table1.AsEnumerable().AsQueryable()
              .GroupBy(groupbyvalue,"it")
              .Select("new ("+groupbyvalue+" as Group, Sum(Value) as TotalValue)");

上記のクエリでは、選択された groupbyvalue (Group) は常に文字列になり、合計は常に double になるため、Result がプロパティ Group (string ) および TotalValue (double)。

私はこれに多くの問題を抱えています。誰か光を当てることができますか?

4

4 に答える 4

43

まず、KeySelect句のように、現在のグループ化された値にアクセスします。

.Select("new (Key as Group, Sum(Value) as TotalValue)");

これでクエリが機能するはずです。より難しい問題は、から継承する動的に生成された型を持つ返されたオブジェクトをDynamicClass静的型に変換する方法です。

オプション1:リフレクションを使用して動的オブジェクトGroupTotalValueプロパティにアクセスします。

オプション2:コンパイルされた式ツリーを使用して軽量コードを生成しGroupTotalValueプロパティにアクセスします。

オプション3:強く型付けされた結果をサポートするようにダイナミックライブラリを変更します。これはかなり単純であることがわかります。

  1. ExpressionParser.Parse()、タイプ引数をプライベートフィールドにキャプチャします。

    private Type newResultType;
    public Expression Parse(Type resultType)
    {
        newResultType = resultType;
        int exprPos = token.pos;
        // ...
    
  2. の終わり近くで、動的タイプにデフォルト設定する前ExpressionParser.ParseNew()に使用を試みます。newResultType

    Expression ParseNew()
    {
        // ...
        NextToken();
        Type type = newResultType ?? DynamicExpression.CreateClass(properties);
        MemberBinding[] bindings = new MemberBinding[properties.Count];
        for (int i = 0; i < bindings.Length; i++)
            bindings[i] = Expression.Bind(type.GetProperty(properties[i].Name), expressions[i]);
        return Expression.MemberInit(Expression.New(type), bindings);
    }
    
  3. 最後に、強く型付けされたバージョンのSelect():が必要です。

    public static IQueryable<TResult> Select<TResult>(this IQueryable source, string selector, params object[] values)
    {
        if (source == null) throw new ArgumentNullException("source");
        if (selector == null) throw new ArgumentNullException("selector");
        LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, typeof(TResult), selector, values);
        return source.Provider.CreateQuery<TResult>(
            Expression.Call(
                typeof(Queryable), "Select",
                new Type[] { source.ElementType, typeof(TResult) },
                source.Expression, Expression.Quote(lambda)));
    }
    

    オリジナルからの唯一の変更は、Select()私たちが参照する場所TResultです。

ここで、返す名前付きタイプが必要です。

    public class Result
    {
        public string Group { get; set; }
        public double TotalValue { get; set; }
    }

更新されたクエリは次のようになります。

    IQueryable<Result> res = table1.AsQueryable()
        .GroupBy(groupbyvalue, "it")
        .Select<Result>("new (Key as Group, Sum(Value) as TotalValue)");
于 2009-09-23T20:33:32.723 に答える
3

次の方法で、返されたデータを List<IExampleInterface> にキャストしました。

1 動的 linq の Select メソッドを拡張して、ジェネリック型をサポートします。ここで最初の回答を参照してください

2 Select メソッドを使用します (dahlbyk の回答の最初の行と非常によく似ています)

Select<dynamic>("new (Key as Group, Sum(Value) as TotalValue)")

複数の列が必要な場合は、次を使用できます。

GroupBy(@"new (Fund, Column1, Column2)", "it").
Select<dynamic>("new (Key.Fund, Key.Column1, Key.Column2, Sum(Value) as TotalValue)")

3 データをリストに変換します。

var data = ...
  GroupBy("...").Select<dynamic>("...").
  Cast<dynamic>().AsEnumerable().ToList();

4 Impromptuを使用して List を List<IExampleInterface> に変換する

var result = new List<IExampleInterface>();

foreach (var d in data)
{
  dynamic r = Impromptu.ActLike<IExampleInterface>(d);
  result.Add(r);
}
于 2012-10-03T09:11:17.060 に答える
1

もう1つの可能性は、DLinqのクエリ言語を拡張してnew、クエリ文字列の句でタイプ名を指定できるようにすることです。

別のstackoverflowの回答でDynamic.csに必要な変更について説明しました。

これにより、次のようなクエリを実行できます。

IQueryable<Result> res 
    = table1.AsQueryable()
    .GroupBy(groupbyvalue, "it")
    .Select("new Result(Key as Group, Sum(Value) as TotalValue)")
    as IQueryable<Result>;
于 2012-01-09T08:47:00.947 に答える