繁体   English   中英

动态 LINQ Any() 返回无效结果

[英]Dynamic LINQ Any() is Returning Invalid Results

问题设置

我正在尝试使用System.Linq.Dynamic.Core package 在我的应用程序中实施验证规则,但我遇到了奇怪的行为。 我的想法是能够从应用程序本身创建和管理这些验证规则。 所以,我的数据库中有一个ValidationRule object 定义为:

public class ValidationRule {
    public string Description { get; set; }
    public string ErrorMessage { get; set; }
    public short Id { get; set; }
    public bool IsActive { get; set; }
    public string Name { get; set; }
    public string NewExpression { get; set; }
    public string OldExpression { get; set; }
}

NewExpressionOldExpression属性包含我想传递给Any()动态版本的表达式。 ValidationRule object 的唯一重要部分是NameErrorMessageNewExpressionOldExpression ,因此我将它们投影到 DTO 中:

public class ValidationRuleDto {
    public string ErrorMessage { get; set; }
    public string Name { get; set; }
    public string NewExpression { get; set; }
    public string OldExpression { get; set; }
}

然后将此 DTO 传递给ValidationRuleHandler以评估 object 的旧实例和新实例,该实例正在使用 DTO 中的表达式进行验证。 ValidationRuleHandler看起来像这样:

public static class ValidationRuleHandler {
    private static readonly ParsingConfig _parsingConfig = new() {
        AreContextKeywordsEnabled = false
    };

    public static ICollection<string> Validate(
        dynamic oldObject,
        dynamic newObject,
        IEnumerable<ValidationRuleDto> rules) => rules.Select(
        _ => {
            var oldResult = new[] {
                oldObject
            }.AsQueryable().Any(_parsingConfig, _.OldExpression);
            var newResult = new[] {
                newObject
            }.AsQueryable().Any(_parsingConfig, _.NewExpression);

            Debug.WriteLine($"Old => {oldObject.StageText} => {_.OldExpression} => {oldResult}");
            Debug.WriteLine($"New => {newObject.StageText} => {_.NewExpression} => {newResult}");
            
            return !(oldResult && newResult)
                ? null
                : $"[{_.Name}] {_.ErrorMessage}";
        }).Where(
        _ => _ != null).ToHashSet();
}

对于传递给Validate()的新旧对象,我将 object 投影到旧快照(来自数据库)和新快照(来自数据库但应用了更改)DTO。 Validate()中,我将每个对象添加到单个项目集合中并将它们转换为IQueryable以便我可以使用动态Any() 我在这里的思考过程是规则的表达式只需要评估为真/假结果,并且由于如果表达式的条件通过Any()将返回真/假,这似乎是 go 最合适的方法。

问题

我遇到的问题是运行应用程序时没有发生我期望的结果。 作为参考,该应用程序是针对 .NET 框架 4.8 的 ASP.NET MVC 5 (5.2.9) 应用程序。 但是,当使用 LINQPad (5.46.00) 测试ValidationRuleHandler时,结果是正确的。 例如,当它处理适用于用户的三个验证规则时,应用程序的Debug语句的 output 如下所示:

  • 旧 => 未售出 => (StageText != "Closed") => True
  • 新 => 已关闭 => (StageText == "已关闭") => 错误错误
  • 旧 => 未售出 => (StageText != "Not Sold") => True错误
  • 新 => 已关闭 => (StageText == "Not Sold") 和 (ReasonNotSoldText == null) => False
  • 旧 => 未售出 => (StageText != "准备开票") => True
  • New => Closed => (StageText == "Ready to Invoice") 和 (PricingMethodText == null) => False

这是完全相同的验证规则和快照对象(完全相同的值)的 LINQPad 结果:

  • 旧 => 未售出 => (StageText != "Closed") => True
  • 新 => 已关闭 => (StageText == "已关闭") => 真
  • 旧 => 未售出 => (StageText != "Not Sold") => False
  • 新 => 已关闭 => (StageText == "Not Sold") 和 (ReasonNotSoldText == null) => False
  • 旧 => 未售出 => (StageText != "准备开票") => True
  • New => Closed => (StageText == "Ready to Invoice") 和 (PricingMethodText == null) => False

如您所见,当从 LINQPad 调用ValidationRuleHandler时,它会正确评估表达式,但从应用程序处理时,它是错误的。

我不明白为什么它会这样。 仔细想想,我看不出有什么问题,LINQPad 的行为符合预期,但应用程序不是,我不知道还能做什么。 如果有人有任何建议,我将不胜感激。 如果有人以前必须处理类似的事情,我也愿意接受替代建议来实现相同的目标。

使用以下示例代码创建 .NET Full Framework 4.8 控制台应用程序时:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;

namespace ConsoleApp48DynamicLinq
{
    public class ValidationRule
    {
        public string Description { get; set; }
        public string ErrorMessage { get; set; }
        public short Id { get; set; }
        public bool IsActive { get; set; }
        public string Name { get; set; }
        public string NewExpression { get; set; }
        public string OldExpression { get; set; }
    }

    public class ValidationRuleDto
    {
        public string ErrorMessage { get; set; }
        public string Name { get; set; }
        public string NewExpression { get; set; }
        public string OldExpression { get; set; }
    }

    public class Test
    {
        public string StageText { get; set; }
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            var old = new Test
            {
                StageText = "Not Sold"
            };

            var @new = new Test
            {
                StageText = "Closed"
            };

            var validation = new ValidationRuleDto
            {
                OldExpression = "(StageText != \"Closed\")",
                NewExpression = "(StageText == \"Closed\")"
            };

            var validations = new[] { validation };

            ValidationRuleHandler.Validate(old, @new, validations);
        }

        public static class ValidationRuleHandler
        {
            private static readonly ParsingConfig ParsingConfig = new ParsingConfig
            {
                AreContextKeywordsEnabled = false
            };

            public static ICollection<string> Validate(
                dynamic oldObject,
                dynamic newObject,
                IEnumerable<ValidationRuleDto> rules) => rules.Select(
                _ =>
                {
                    var oldResult = new[]
                    {
                        oldObject
                    }.AsQueryable().Any(ParsingConfig, _.OldExpression);
                    var newResult = new[]
                    {
                        newObject
                    }.AsQueryable().Any(ParsingConfig, _.NewExpression);

                    Console.WriteLine($"Old => {oldObject.StageText} => {_.OldExpression} => {oldResult}");
                    Console.WriteLine($"New => {newObject.StageText} => {_.NewExpression} => {newResult}");

                    return !(oldResult && newResult) ? null : $"[{_.Name}] {_.ErrorMessage}";
                }).Where(_ => _ != null).ToHashSet();
        }
    }
}

它似乎工作正常:

在此处输入图像描述

因此,经过数小时尝试不同的解决方案以查看失败的确切位置后,没有任何效果,直到我将表达式更改为使用Equals() 在那之后立即工作,我不确定为什么会这样: (StageText.Equals("Closed")) ; 有效,这个: (StageText == "Closed") ; 没有。

当我在 LINQPad 中测试它而不是在应用程序中测试时,为什么原始方式有效,我仍然感到困惑。 @Stef 也证实它有效,所以我很困惑。 也许它与从数据库中提取的快照值有关,或者也与从数据库中提取的验证规则表达式有关?

无论如何,它适用于Equals()所以我正在使用它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM