gpt4 book ai didi

c# - 将 Array 匹配到 SqlParser.Parser 的输出?

转载 作者:行者123 更新时间:2023-11-30 17:27:44 28 4
gpt4 key购买 nike

背景

作为面向数据库的应用程序的一部分,我们发现有必要构造参数化查询并将其传递到其他 EntityFramework 应用程序中,通常用于桥接多个客户端数据库。我们通过非常标准的语法来做到这一点:

context.Database.SqlQuery<ReturnModel>(queryString, sqlParameters)

queryString 是一个字符串,sqlParameters 是一个 SqlParameter 对象数组。

测试

当我们在应用程序中构建额外的自动化测试时,我发现将 SqlParser 用作“离线”测试器很有帮助。它不会捕获所有内容,但我可以:

var parseResults = Parser.Parse(queryString);
Assert.That(parseResults.Errors, Is.Empty);

并确保我们没有在参数化查询字符串中引入任何语法错误。

我还希望能够验证我们在生成的参数列表中没有任何遗漏的参数;查询字符串中预期的参数,但未提供。有什么方法可以将 sqlParameters 与 parseResults 中的内容进行匹配来执行此操作,或者利用 Microsoft.SqlServer.Management 库的其他功能?

最佳答案

SqlParser 是一个经典的解析器,带有用于处理结果的访问者界面。唯一美中不足的是公共(public)文档,它似乎与发布不同步,而且通常缺乏任何和所有示例,以至于它几乎没有用。我假设此处使用的解析器是您可以在 Microsoft.SqlServer.SqlParser NuGet package 中找到的解析器。 .早期版本作为独立安装分发,它们不使用相同的类型。

首先,假设一个简单的查询,我们可以通过访问所有变量声明和引用并消除对局部声明变量的引用来获取所有参数的列表——这些必须是参数。

class ParameterVisitor : SqlCodeObjectRecursiveVisitor {
HashSet<string> referencedVariables = new HashSet<string>();
public override void Visit(SqlScalarVariableRefExpression codeObject) {
referencedVariables.Add(codeObject.VariableName);
}

HashSet<string> declaredVariables = new HashSet<string>();
public override void Visit(SqlVariableDeclaration codeObject) {
declaredVariables.Add(codeObject.Name);
}

public override void Visit(SqlBatch codeObject) {
base.Visit(codeObject);
parameters = referencedVariables.Except(declaredVariables).ToList();
}

List<string> parameters;
public IEnumerable<string> Parameters => parameters;
}

用作(例如):

internal static class ParseResultsExtensions {
public static IEnumerable<string> GetParameters(this ParseResult p) {
var pv = new ParameterVisitor();
p.Script.Accept(pv);
return pv.Parameters;
}
}

string queryString = @"DECLARE @notAParameter INT; SELECT @c, @b, @a, @notAParameter";
var myParameterCollection = new[] {
new SqlParameter("@a", SqlDbType.Int),
new SqlParameter("@b", SqlDbType.Int),
new SqlParameter("@c", SqlDbType.Int),
};

ParseResult parseResults = Parser.Parse(queryString);
Assert.That(parseResults.Errors, Is.Empty);

var expected = myParameterCollection.Select(p => p.ParameterName);
var actual = parseResults.GetParameters();
Assert.That(actual, Is.EquivalentTo(expected));

用信息量更大的断言调味。

令人沮丧的是,SqlScalarVariableRefExpression 有一个 BoundVariable 属性,它似乎能够将引用链接到它们的声明。不幸的是,使用它涉及使用 BinderProvider,它从实际数据库中提取一整套元数据(因此它可以将标识符绑定(bind)到数据库对象)。关于这个的文档太少了,如果你只想做一些本地解析,我无法解码如何正确使用它。

这段代码也不完整,因为它只处理标量变量——添加对表变量的支持留给读者作为练习。

关于c# - 将 Array<SqlParameter> 匹配到 SqlParser.Parser 的输出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54449987/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com