实体框架使用CompiledQuery但允许运行时筛选器值

时间:2011-05-12 05:47:21

标签: entity-framework-4.1 linq-expressions compiled-query

我正在尝试使用实体框架重构一个繁琐的LINQ-to-SQL数据层。模型背后的数据库模式很大,典型查询可能有20到30个包含。 EF为这些查询生成了大量的SQL语句,迄今为止最大的是4k行,但它们仍然及时执行,因此这不是问题。

问题是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();
        }
    }
}

有没有什么方法可以在编译的查询中包含我的过滤器表达式,并且能够在执行查询时设置过滤器表达式的值?

2 个答案:

答案 0 :(得分: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));

答案 1 :(得分: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));

我们将开始讨论使用数据库视图来解决首先需要使用编译查询的问题。如果不必编译L2E查询以避免延迟近2秒,则可以添加可重用表达式过滤器。