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

63lcw9qa  于 2022-12-06  发布在  其他
关注(0)|答案(2)|浏览(131)
问题设置

我尝试使用System.Linq.Dynamic.Core包在我的应用中实现验证规则,但是遇到了奇怪的行为。我的想法是能够在应用本身中创建和管理这些验证规则。因此,我在数据库中定义了一个ValidationRule对象:

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对象的重要部分只有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,以使用来自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()的新旧对象,我将对象投影到旧快照中(从数据库原样)和新快照在Validate()中,我将每个对象添加到单个项集合中,并将它们转换为IQueryable,以便可以使用动态Any()。我在这里的思路是,规则的表达式只需要计算出true/false结果,并且由于如果表达式的条件通过,Any()将返回true/false,因此这似乎是最合适的方法。
问题
我遇到的问题是,在运行应用程序时,我所期望的结果并没有出现。(5.2.9)应用程序。但是,使用LINQPad时(5.46.00)来测试ValidationRuleHandler,结果是正确的。例如,以下是应用程序中Debug语句的输出:s处理应用于用户的三个验证规则:

  • 旧=〉未售出=〉(阶段文本!=“已关闭”)=〉True
  • 新建=〉已关闭=〉(阶段文本==“已关闭”)=〉错误错误
  • 旧版=〉未售出=〉(StageText!=“未售出”)=〉正确错误
  • 新建=〉已关闭=〉(阶段文本==“未售出”)和(未售出原因文本==空)=〉假
  • 旧=〉未售出=〉(StageText!=“准备开票”)=〉True
  • 新建=〉已关闭=〉(阶段文本==“准备开票”)和(定价方法文本==空)=〉假

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

  • 旧=〉未售出=〉(阶段文本!=“已关闭”)=〉True
  • 新建=〉已关闭=〉(阶段文本==“已关闭”)=〉True
  • 旧=〉未售出=〉(阶段文本!=“未售出”)=〉假
  • 新建=〉已关闭=〉(阶段文本==“未售出”)和(未售出原因文本==空)=〉假
  • 旧=〉未售出=〉(StageText!=“准备开票”)=〉True
  • 新建=〉已关闭=〉(阶段文本==“准备开票”)和(定价方法文本==空)=〉False

正如您所看到的,当从LINQPad调用ValidationRuleHandler时,它正确地计算表达式,但当从应用程序处理时,它是错误的。
我不明白为什么它会这样。仔细想想,我看不出有什么问题,LINQPad的表现和预期的一样,但应用程序却不是,我不知道还能做什么。如果有人有任何建议,我将不胜感激。如果有人以前不得不处理类似的事情,我也愿意接受替代建议,以实现同样的目标。

mftmpeh8

mftmpeh81#

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

看起来效果不错:

7lrncoxx

7lrncoxx2#

因此,在尝试了许多个小时的不同解决方案来查看它到底在哪里失败之后,没有任何效果,直到我将表达式改为使用Equals()。之后立即工作了,我不知道为什么会这样:(StageText.Equals("Closed"));的工作原理和以下内容:(StageText == "Closed");不会。
我仍然很困惑,为什么我在LINQPad中测试时,原来的方法可以工作,而在应用程序中却不行。@Stef也证实了它的工作,所以我很困惑。也许它与从数据库中提取快照值有关,或者也与从数据库中提取验证规则表达式有关?
无论如何,它与Equals()一起工作,所以我正在使用它。

相关问题