次のような非常に単純なエンティティがあるとします。
public class TestGuy
{
public virtual long Id {get;set;}
public virtual string City {get;set;}
public virtual int InterestingValue {get;set;}
public virtual int OtherValue {get;set;}
}
この考案されたサンプル オブジェクトは、(Fluent を使用して) NHibernate でマップされ、正常に動作します。
いくつかのレポートを行う時間です。この例では、「testGuys」は、いくつかの条件が既に適用されている IQueryable です。
var byCity = testGuys
.GroupBy(c => c.City)
.Select(g => new { City = g.Key, Avg = g.Average(tg => tg.InterestingValue) });
これはうまくいきます。NHibernate Profiler では、正しい SQL が生成されていることを確認でき、結果は期待どおりです。
自分の成功に触発されて、もっと柔軟にしたいと思っています。ユーザーが OtherValue と InterestingValue の平均を取得できるように、構成可能にしたいと考えています。難しいことではありませんが、Average() の引数は Func のようです (この場合、値は int であるため)。簡単です。何らかの条件に基づいて Func を返すメソッドを作成し、それを引数として使用することはできませんか?
var fieldToAverageBy = GetAverageField(SomeEnum.Other);
private Func<TestGuy,int> GetAverageField(SomeEnum someCondition)
{
switch(someCondition)
{
case SomeEnum.Interesting:
return tg => tg.InterestingValue;
case SomeEnum.Other:
return tg => tg.OtherValue;
}
throw new InvalidOperationException("Not in my example!");
}
そして、他の場所では、これを行うことができます:
var byCity = testGuys
.GroupBy(c => c.City)
.Select(g => new { City = g.Key, Avg = g.Average(fieldToAverageBy) });
まあ、私はそれができると思いました。ただし、これを列挙すると、NHibernate は次のように反応します。
Object of type 'System.Linq.Expressions.ConstantExpression' cannot be converted to type 'System.Linq.Expressions.LambdaExpression'.
したがって、舞台裏で、最初のケースでは私のラムダを受け入れるが、2番目のケースではNHibernateがSQLに変換できないものにする何らかの変換またはキャストまたはそのようなことが起こっていると推測しています。
私の質問は単純であるといいのですが、NHibernate 3.0 LINQ サポート (.Query() メソッド) がこれを SQL に変換するときに、GetAverageField 関数が Average() のパラメーターとして機能するものを返すにはどうすればよいですか?
どんな提案も歓迎します、ありがとう!
編集
彼の回答での David B からのコメントに基づいて、私はこれを詳しく調べました。Func が正しい戻り値の型であるという私の仮定は、Average() メソッドで取得したインテリセンスに基づいていました。Queryable 型ではなく、Enumerable 型に基づいているようです。それは奇妙です..物事をもう少し詳しく見る必要があります。
GroupBy メソッドには、次のリターン シグネチャがあります。
IQueryable<IGrouping<string,TestGuy>>
つまり、IQueryable が返されるはずです。ただし、次の行に進みます。
.Select(g => new { City = g.Key, Avg = g.Average(tg => tg.InterestingValue) });
新しい { } オブジェクト定義内の g 変数のインテリセンスを確認すると、実際には IGrouping 型 (IQueryable> ではありません) としてリストされています。これが、呼び出された Average() メソッドが Enumerable であり、David B によって提案された Expression パラメーターを受け入れない理由です。
どういうわけか、私のグループの値は、どこかで IQueryable としてのステータスを失ったようです。
少し興味深いメモ:
Select を次のように変更できます。
.Select(g => new { City = g.Key, Avg = g.AsQueryable<TestGuy>().Average(fieldToAverageBy) });
そして今、それはコンパイルされます! 黒魔術!ただし、NHibernate はもはや私を愛しておらず、次の例外を与えるため、問題は解決しません。
Could not parse expression '[-1].AsQueryable()': This overload of the method 'System.Linq.Queryable.AsQueryable' is currently not supported, but you can register your own parser if needed.
困惑するのは、Average() メソッドにラムダ式を指定するとこれが機能することですが、同じ式を引数として表す簡単な方法が見つからないことです。私は明らかに何か間違ったことをしていますが、何が見えません...!?
私は途方に暮れています。助けて、ジョン・スキート、あなたが私の唯一の希望です!;)