BQL 解析和验证

任何 Acumatica 应用程序开发人员都花费大量时间编写 BQL 代码。与此同时,并非所有人都知道 BQL 类型如何在幕后工作的基本细节。

BQL 的核心是两个关键方法:Parse()Verify(),由 IBqlCreator 接口声明。大多数常用的 BQL 类型,如 Where<>And<>Or<> 等,都来自这个界面。

应该承认,这些方法历史上坚持的名称不是很具描述性。可以说更好的替代名称是 PrepareCommandTextEvaluate

解析

public void Parse(
    PXGraph graph, 
    List<IBqlParameter> pars, 
    List<Type> tables, 
    List<Type> fields, 
    List<IBqlSortColumn> sortColumns, 
    StringBuilder text, 
    BqlCommand.Selection selection)

Parse() 的唯一目的是将 BQL 转换为要发送到 DBMS 的 SQL 命令。因此,此方法接受表示当前正在构造的 SQL 命令的 StringBuilder 参数,BQL 创建者将其附加到其自身的 SQL 文本表示形式。

例如,And<> 谓词的 Parse() 方法会将 AND 附加到命令文本,并递归请求所有嵌套 BQL 创建者的翻译。

特别是,And<ARRegister.docType, Equal<ARDocType.invoice>> 将转化为像 "AND "ARRegister.DocType = 'AR'" 这样的东西。

校验

public void Verify(
    PXCache cache, 
    object item, 
    List<object> pars, 
    ref bool? result, 
    ref object value)

Parse() 相比,Verify() 纯粹在应用程序级别运行。

给定记录(例如,ARRegister 对象),它可用于计算其上的表达式,包括计算公式和评估条件。

result 参数用于存储布尔条件评估结果。它主要由谓词 BQL 创建者使用,例如 Where<>

value 参数用于存储表达式计算结果。例如,BQL Constant<string>value 是该常量的字符串表示。

大多数情况下,BQL 创建者会影响结果或值,但很少会影响两者。

Verify() 方法的一个值得注意的用法是静态 BqlCommand.Meet() 方法,由 PXCache 用来确定给定项是否满足 BQL 命令:

public bool Meet(PXCache cache, object item, params object[] parameters)
{
    List<object> pars = new List<object>(parameters);
    bool? result = null;
    object value = null;
    try {
        Verify(cache, item, pars, ref result, ref value);
    }
    catch (SystemException ex) {
        throw new PXException(String.Format("BQL verification failed! {0}", this.ToString()), ex);
    }
    return result == null || result == true;
}

结论

BQL 创建者的真正力量和美丽在于,它们中的大多数可以在数据库和应用程序级别使用,从而实现 Acumatica 的缓存合并机制,并为代码可重用性提供了很好的机会。

例如,当你从数据库中选择记录时,BQL 命令的 Where<> 子句:

  • 将提供 Parse() 在命令准备期间将自身转换为 SQL 文本。
  • 将在缓存合并期间提供 Verify() 以确定哪些项目已经驻留在缓存 Meet() Where<> 子句条件中,以便将此类缓存项目包含到结果集中。