0

面倒な LINQ-to-SQL データ レイヤーをエンティティ フレームワークでリファクタリングしようとしています。モデルの背後にあるデータベース スキーマは大きく、典型的なクエリには 20 から 30 のインクルードが含まれる場合があります。EF は、このようなクエリに対して大量の SQL ステートメントを生成します。これまでで最大のものは 4,000 行ですが、それでもタイムリーに実行されるため、問題にはなりません。

問題は、EF がクエリを生成するのに最大 4 秒または 5 秒かかるということです。これを克服するために、CompileQuery を使用しました。問題は、既存の L2S データレイヤーに、ユーザー入力に応じてクエリに適用できるフィルターが多数あることです。これらのフィルターの単一の値は、実行時に設定する必要があります。

以下のコードは、最初の静的値がクエリにコンパイルされるため機能しませんが、私がやろうとしていることを示しています。

public static class DataLayer
{
    static Func<MyEntities, int, IQueryable<Prescription>> compiledQuery;

    static int? FilterHpID;
    static Expression<Func<Prescription, bool>> filter1 = x => (FilterHpID == null || x.Prescriber.HPID == FilterHpID);

    static DateTime? FilterDateTime;
    static Expression<Func<Prescription, bool>> filter2 = x => (FilterDateTime == null || x.DateTimeDispensed > FilterDateTime);

    public static List<Prescription> Get(int patientID, int? hpID, DateTime? dispensed)
    {
        FilterHpID = hpID;
        FilterDateTime = dispensed;

        if (compiledQuery == null)
        {
            compiledQuery = System.Data.Objects.CompiledQuery.Compile((MyEntities entities, int id) =>
                        (from pre in entities.Prescription
                         where pre.PatientID == id
                         select pre)
                         .Where(filter1)
                         .Where(filter2));
        }

        using (MyEntities entities = new MyEntities())
        {
            return compiledQuery(entities, patientID).ToList();
        }
    }
}

コンパイルされたクエリにフィルター式を含め、クエリの実行時にフィルター式に値を設定できる方法はありますか?

4

2 に答える 2

0

高低を検索した結果、コンパイルされたクエリで再利用可能な式を使用する方法はなく、パラメーターを必要とする式も使用できないという結論に達しました。

以下のコードの意図は、どのような形や方法でも実現できません。

static Expression<Func<Prescription, bool>> filter1 = x => (FilterHpID == null || x.Prescriber.HPID == 1);

compiledQuery = System.Data.Objects.CompiledQuery.Compile((MyEntities entities, int id) =>
                    (from pre in entities.Prescription
                     where pre.PatientID == id
                     select pre)
                     .Where(filter1));

最初にコンパイル済みクエリを使用する必要性を回避する方法として、データベース ビューを使用する方法を見ていきます。2 秒近くの遅延を回避するために L2E クエリをコンパイルする必要がない場合は、再利用可能な式フィルターを追加できます。

于 2011-05-13T03:45:55.463 に答える
0

フィルターは、コンパイルされたクエリの一部である必要があり、その後、クエリを呼び出すときに設定できます。次のようなものを使用できると思います:

public static IQueryable<Prescription> Filter1(this IQueryale<Prescription> query, 
    DateTime? param)
{
    return query.Where(x => (param == null || x.Prescriber.HPID == param));
}

次に、コンパイルされたクエリを次のように定義できるはずです。

 compiledQuery = System.Data.Objects.CompiledQuery
                       .Compile((MyEntities entities, int id, DateTime? param) =>
                           (from pre in entities.Prescription
                            where pre.PatientID == id
                            select pre)
                           .Filter1(param));

通常のクエリで動作しますが、コンパイルされたクエリで試したことはありません。うまくいかない場合は、コンパイルされたクエリにフィルター式を直接配置する必要があります。

 compiledQuery = System.Data.Objects.CompiledQuery
                       .Compile((MyEntities entities, int id, DateTime? param) =>
                           (from pre in entities.Prescription
                            where pre.PatientID == id
                            select pre)
                           .Where(x => (param == null || x.Prescriber.HPID == param));
于 2011-05-12T08:21:37.553 に答える