实体框架使用 CompiledQuery 但允许运行时过滤器值

发布于 2024-11-06 10:55:43 字数 1554 浏览 0 评论 0原文

我正在尝试使用实体框架重构繁琐的 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();
        }
    }
}

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

I'm attempting to refactor a cumbersome LINQ-to-SQL data layer with an entity framework one. The database schema behind the model is big and a typical query might have 20 to 30 Includes. The EF generates massive SQL statements for such queries, the biggest so far has been 4k lines, but they still execute in a timely fashion so that's not a problem.

The problem is that the EF takes a long time, up to 4 or 5 seconds to generate the query. To overcome that I've used CompileQuery. The problem then is that the existing L2S datalayer has a lot of filters that can be applied to a query depending on user input. A single value in those filters needs to be set at runtime.

The code below doesn't work because the initial static values get compiled into the query but it demonstrates what I'm attempting to do.

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

Is there any way I can include my filter expressions in the compiled query AND be able to set values on the filter expressions when executing the query?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

半步萧音过轻尘 2024-11-13 10:55:43

过滤器必须是已编译查询的一部分,之后您可以在调用查询时设置它们。我认为你可以使用类似的东西:

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));

Filters must be part of the compiled query and after that you can set them when calling the query. I think you can use something like:

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

Then you should be able to define your compiled query as:

 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));

It works with normal queries but I have never tried it in compiled queries. If it doesn't work you must place filter expression directly in the compiled query:

 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));
傾城如夢未必闌珊 2024-11-13 10:55:43

经过高低搜索后,我得出的结论是,没有办法能够在编译的查询中使用可重用的表达式,更不用说需要参数的表达式了。

以下代码的意图不可能以任何形式或方式实现。

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 秒的延迟,则可以添加可重用的表达式过滤器。

After searching high and low the conclusion I have come to is there is no way to be able to employ reusable expressions in a compiled query let alone expressions requiring a parameter.

The intent of the code below is not possible in any shape or manner.

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));

We're going to go off and look at using database views as a way around the need to use compiled queries in the first place. If the L2E queries don't have to be compiled to avoid taking a nearly 2 second delay then reusable expression filters can be added.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文