[英]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; }
}
NewExpression
和OldExpression
屬性包含我想傳遞給Any()
動態版本的表達式。 ValidationRule
object 的唯一重要部分是Name
、 ErrorMessage
、 NewExpression
和OldExpression
,因此我將它們投影到 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 如下所示:
這是完全相同的驗證規則和快照對象(完全相同的值)的 LINQPad 結果:
如您所見,當從 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.