簡體   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