2

式ツリーを手動で組み合わせて、標準のlinq演算子を使用しているように見えるレベルのモジュール性を実現しようとしています。このコードは基本的に、1つの式を使用して、他の2つの式のどちらを呼び出すかを決定する式ツリーを作成します。他の式の1つには、別の式を使用してそれ自体が取得される追加のパラメーターが必要です。このパラメーターは複数の値を取得するために使用されますが、アクセスごとにパラメーターを取得する式が繰り返されます。説明をわかりやすくするために、コードと出力を含めました。

public void Test() {
    var parameters = ProjectionOne.Parameters;
    Expression<Func<Foo, bool>> isType = f => f.TypeId == 1;
    Expression<Func<Foo, Satellite>> satSelector = f => f.Satellites.Single();
    var satelliteSelector = Expression.Invoke(satSelector, parameters[0]);
    var test = Expression.Lambda<Func<Foo, Bar>>(
        Expression.Condition(
            Expression.Invoke(isType, parameters[0]),
            Expression.Invoke(ProjectionOne, parameters[0]),
            Expression.Invoke(ProjectionTwo, parameters[0], satelliteSelector)), parameters);
}

public Expression<Func<Foo, Bar>> ProjectionOne {
    get {
        return foo => new Bar() {
            Id = foo.Id
        };
    }
}

public Expression<Func<Foo, Satellite, Bar>> ProjectionTwo {
    get {
        return (foo, sat) => new Bar() {
            Id = foo.Id,
            Start = sat.Start,
            End = sat.End
        };
    }
}

データベースでこのクエリを実行すると、SQLは次のように生成されます。

SELECT [t0].[value], [t0].[value2] AS [Start], [t0].[value3] AS [End], [t0].[Id] AS [Id]
FROM (
    SELECT 
        (CASE 
            WHEN [t0].[TypeId] = @p0 THEN 1
            WHEN NOT ([t0].[TypeId] = @p0) THEN 0
            ELSE NULL
         END) AS [value], (
        SELECT [t2].[Start]
        FROM [dbo].[Satellite] AS [t2]
        WHERE [t2].[Id] = [t0].[Id]
        ) AS [value2], (
        SELECT [t2].[End]
        FROM [dbo].[Satellite] AS [t2]
        WHERE [t2].[Id] = [t0].[Id]
        ) AS [value3], [t0].[Id]
    FROM [dbo].[Foo] ) AS [t0]

問題は、サブ選択が重複していることです。1つは「開始」値を取得し、もう1つは「終了」値を取得します。それらが両方とも単一のサブ選択から取得された方がはるかに良いでしょう。これを強制するために式ツリーの構造を変更するにはどうすればよいですか?また、このクエリを実行する簡単な方法があることも理解していますが、これはここに示されていないより大きなフレームワークの一部であり、再利用可能な式の大規模なセットから式ツリーを手動で組み立てることによってのみ実現できます。

4

1 に答える 1

1

できることはすべて既に行っていると思います (すでにプロジェクションを使用しているため、エンジンは個々のサブ選択として表現することを選択しています)

私が考えることができる唯一の他のことは、(たとえば)テーブル値のUDFを(データコンテキストを介して)使用して開始/終了を取得することです-それがクエリにフラット化されるかどうかを確認してください。

クエリのプロファイルを作成し、好みのレイアウトと比較しましたか? プロファイルが同一である可能性があります (つまり、TSQL オプティマイザーが処理したため)。その場合、過度に心配する必要はありません。

于 2009-02-24T08:42:04.590 に答える