[英]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.