在实体类中使用方法定义的查询避免查询客户端评估错误 [英] Avoid Query Client Evaluation error on a query with method definition inside entity class

查看:54
本文介绍了在实体类中使用方法定义的查询避免查询客户端评估错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

.NET Core 2.1 项目中,我在SQL Server数据库上使用带有命令模式的EF Core(使用 MediatR 库).

In a .NET Core 2.1 project, I'm using EF Core with Command pattern (using MediatR library) on a SQL Server database.

我通过使用以下设置来设置项目以避免客户端查询评估:

I setup the project to avoid client query evaluation, by using these settings:

var phaseOptions = new DbContextOptionsBuilder<PhaseDbContext>().UseSqlServer(configuration.GetConnectionString("PhaseDbContext"),
        sqlServerOptions => sqlServerOptions
            .EnableRetryOnFailure(
                maxRetryCount: 5,
                maxRetryDelay: TimeSpan.FromSeconds(30),
                errorNumbersToAdd: null))
    .ConfigureWarnings(warnings => warnings
        .Throw(RelationalEventId.QueryClientEvaluationWarning)) // Disable Client query evaluation
    .Options;

现在,我在此查询中得到一个QueryClientEvaluationException:

Now I get a QueryClientEvaluationException with this query:

var articleCodes = await PhaseContext.PhaseArticles
    .Where(a => !request.ArticleFamily.HasValue || a.GetArticleFamily() == request.ArticleFamily.Value)
    .ToListAsync(cancellationToken);

问题出在a.GetArticleFamily()方法调用上,因为该方法现在在PhaseArticle实体类内部定义如下:

The problem is on the a.GetArticleFamily() method call, because that method now is defined as follows, inside the PhaseArticle entity class:

public class PhaseArticle
{
    public int Id { get; set; }
    public string Code { get; set; }
    public string Description { get; set; }
    public string UnitOfMeasure { get; set; }
    public string Category { get; set; }
    public string Group { get; set; }
    public string Family { get; set; }
    public double UnitCost { get; set; }
    public string AdditionalDescription { get; set; }
    public string ExternalCode { get; set;}
    public string ColorCode { get; set;}
    public string Note { get; set; }

    public ArticleFamily GetArticleFamily()
    {
        switch (Family)
        {
            case "CEL":
                return ArticleFamily.Cell;
            case "STR":
                return ArticleFamily.String;
            case "RAW":
                return ArticleFamily.OtherRawMaterial;
            case "SFP":
                return ArticleFamily.SemiFinishedPanel;
            case "FP":
                return ArticleFamily.FinishedPanel;
            default:
                return ArticleFamily.Other;
        }
    }
}

现在,我想知道是否可以通过某种方式重构GetArticleFamily()方法(并可能远离实体类)来保留QueryClientEvaluationWarning选项.

Now, I want to know if it is possible to keep the QueryClientEvaluationWarning option by somehow refactoring (and probably moving away from the entity class) the GetArticleFamily() method.

@StriplingWarrior我已经根据您对ValueConverter()的建议再次更新了代码,但现在却出现此错误:

@StriplingWarrior I've updated again the code with your suggestion about ValueConverter(), but now it is giving this error:

无法将Lambda表达式转换为表达式树.

Cannot convert Lambda expression into a tree of expressions.

更新2019/02/25

按照@StriplingWarrior的建议,我正在尝试编写一个自定义转换器,但无法使我的代码编译.

Update 2019/02/25

Following @StriplingWarrior suggestion, I'm trying to write a custom converter but I'm not able to make my code compile.

以下代码的错误与第一个switch块的返回值(它是string,但它应该是enum)有关,并且与预期的第二个开关块的输入值(它是一个string,但应该是一个enum).

The error with the code below is about return value of the first switch block (it's string but it is expected to be an enum) and about the expected input value of the second switch block (it's a string but it is expected to be an enum).

这是代码:

public static void ApplyPhaseConversions<T>(this ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<PhaseArticle>()
        .Property(e => e.Family)
        .HasConversion(new ValueConverter<ArticleFamily, string> {
            v =>
            {
                switch (v)
                {
                    case ArticleFamily.Cell:
                        return "CEL";
                    case ArticleFamily.String:
                        return "STR";
                    case ArticleFamily.OtherRawMaterial:
                        return "RAW";
                    case ArticleFamily.SemiFinishedPanel:
                        return "SFP";
                    case ArticleFamily.FinishedPanel:
                        return "FP";
                    default:
                        return "";
                }
            },
            v =>
            {
                switch (v)
                {
                    case "CEL":
                        return ArticleFamily.Cell;
                    case "STR":
                        return ArticleFamily.String;
                    case "RAW":
                        return ArticleFamily.OtherRawMaterial;
                    case "SFP":
                        return ArticleFamily.SemiFinishedPanel;
                    case "FP":
                        return ArticleFamily.FinishedPanel;
                    default:
                        return ArticleFamily.Other;
                }
            }});
}

推荐答案

最后,就像@StriplingWarrior所说的那样,解决方案就已经存在了.

Finally, the solution was almost there, as also @StriplingWarrior said.

由于C#编译器的局限性,例如不能为该代码创建表达式树,解决方案是将转换代码工厂化为方法,然后在HasConversion中调用它们.

Due to limitations in the C# compiler, such that it can't create expression trees for this code, the solution is to factory the conversion code into methods and then call those in HasConversion.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<PhaseArticle>()
        .Property(e => e.Family)
        .HasConversion(new ValueConverter<ArticleFamily, string>(
            v => StringFromArticleFamily(v),
            v => ArticleFamilyFromString(v));
}

private static ArticleFamily ArticleFamilyFromString(string family)
{
    switch (family)
    {
        case "CEL":
            return ArticleFamily.Cell;
        case "STR":
            return ArticleFamily.String;
        case "RAW":
            return ArticleFamily.OtherRawMaterial;
        case "SFP":
            return ArticleFamily.SemiFinishedPanel;
        case "FP":
            return ArticleFamily.FinishedPanel;
        default:
            return ArticleFamily.Other;
    }
}

private static string StringFromArticleFamily(ArticleFamily articleFamily)
{
    switch (articleFamily)
    {
        case ArticleFamily.Cell:
            return "CEL";
        case ArticleFamily.String:
            return "STR";
        case ArticleFamily.OtherRawMaterial:
            return "RAW";
        case ArticleFamily.SemiFinishedPanel:
            return "SFP";
        case ArticleFamily.FinishedPanel:
            return "FP";
        default:
            return "";
    }
}

这篇关于在实体类中使用方法定义的查询避免查询客户端评估错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆