テーブルの列から取得した値に基づいて文字列値を取得する「S」という名前の列をテーブルに挿入します。
例:for each ID (a.z)
別のテーブルに保存されている文字列値を取得したい。文字列値は、Linqクエリを介して取得する別のメソッドから返されます。
これは、取得する必要がある情報の構造です。
a.zはテーブル#1の最初の正方形のIDであり、このIDからテーブル#2の別のIDを取得し、それから列 'S'の下に表示する必要がある文字列値を取得できます。
_var q = (from a in v.A join b in v.B
on a.i equals b.j
where a.k == "aaa" && a.h == 0
select new {T = a.i, S = someMethod(a.z).ToString()})
return q;
_
S = someMethod(a.z).ToString()
行により、次のエラーが発生します。
タイプ 'System.Data.Linq.SqlClient.SqlColumn'のオブジェクトをタイプ 'System.Data.Linq.SqlClient.SqlMethodCall'にキャストできません。
データベース側ではメソッド呼び出しが意味をなさないため、Linq-to-Objects
_コンテキストでメソッド呼び出しを実行する必要があります-AsEnumerable()
を使用してこれを行うことができます-基本的にクエリの残りは_Linq-to-Objects
_を使用してメモリ内コレクションとして評価され、期待どおりにメソッド呼び出しを使用できます。
_var q = (from a in v.A join b in v.B
on a.i equals b.j
where a.k == "aaa" && a.h == 0
select new {T = a.i, Z = a.z })
.AsEnumerable()
.Select(x => new { T = x.T, S = someMethod(x.Z).ToString() })
_
これを2つのステートメントに分割します。クエリの結果(データベースにヒットするもの)を返し、別のステップで2回目に結果を列挙して、翻訳を新しいオブジェクトリストに変換します。この2番目の「クエリ」はデータベースにヒットしないため、その内部でsomeMethod()
を使用できます。
Linq-to-Entitiesは、C#からデータベースへのクエリへの移行を非常にシームレスにするため、少し奇妙なことです。その結果、「このC#をすべて実際にSQLとして実行できますか?」と自問する必要があります。できない場合-内部でsomeMethod()
を呼び出している場合、クエリに問題が発生します。そして、通常の解決策はそれを分割することです。
(.AsEnumerable()
を使用した@BrokenGlassからの他の答えは、基本的にそれを行う別の方法です。)
これは古い質問ですが、「ハック」に言及している人は誰もいません。これにより、選択中に反復せずにメソッドを呼び出すことができます。アイデアはコンストラクターを使用することで、コンストラクターで好きなものを呼び出すことができます(少なくとも、NHibernateを使用したLINQでは正常に動作しますが、LINQ2SQLまたはEFについてはわかりませんが、同じであると思います)。以下にベンチマークプログラムのソースコードがありますが、私の場合の反復アプローチはコンストラクターアプローチの約2倍遅いようです。不思議はないと思います-私のビジネスロジックは最小限でしたので、反復やメモリ割り当てなどが重要です。
また、私はこれがデータベース上で実行されることを試みるべきではない、と言うより良い方法があることを望みました、
// Here are the results of selecting sum of 1 million ints on my machine:
// Name Iterations Percent
// reiterate 294 53.3575317604356%
// constructor 551 100%
public class A
{
public A()
{
}
public A(int b, int c)
{
Result = Sum(b, c);
}
public int Result { get; set; }
public static int Sum(int source1, int source2)
{
return source1 + source2;
}
}
class Program
{
static void Main(string[] args)
{
var range = Enumerable.Range(1, 1000000).ToList();
BenchmarkIt.Benchmark.This("reiterate", () =>
{
var tst = range
.Select(x => new { b = x, c = x })
.AsEnumerable()
.Select(x => new A
{
Result = A.Sum(x.b, x.c)
})
.ToList();
})
.Against.This("constructor", () =>
{
var tst = range
.Select(x => new A(x, x))
.ToList();
})
.For(60)
.Seconds()
.PrintComparison();
Console.ReadKey();
}
}