关于 azure cosmosdb:如何在 Cosmos DB SDK v3 中使用 LINQ 调用 UDF?

How to invoke a UDF with LINQ in Cosmos DB SDK v3?

Cosmos DB 的 LINQ 到 SQL 转换的文档状态:

User-Defined Function Extension function: Supports translation from the stub method UserDefinedFunctionProvider.Invoke to the corresponding user-defined function.

但是,此功能在 .NET SDK v3 中不可公开访问(尽管它在 v2 中)。那么在修复错误之前有什么解决方法?


我正在使用 Microsoft.Azure.Cosmos 3.22.1 SDK 作为 UDF(用户定义函数)的示例,它运行良好。

我使用了微软的例子。

当然也可以将UDF与where子句结合使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
CosmosClient client = new(endpoint, key);

IQueryable<Product> queryable = client
    .GetContainer("database","products")
    .GetItemLinqQueryable<Product>()
    .Select(b => new Product{ id = b.id, price = b.price, priceWithTax = CosmosLinq.InvokeUserDefinedFunction("tax", b.price).ToString() });

var productIterator = queryable.ToFeedIterator<Product>();
while (productIterator.HasMoreResults)
{
    var responseMessage = await productIterator.ReadNextAsync();
    Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(responseMessage));
}

有几种解决方法:

  • 不要使用 LINQ。
  • 使用 LINQ 但不调用 UDF,然后使用 query.ToQueryDefinition.QueryText 获取查询字符串并对其进行操作以在您需要它们的位置插入 UDF 调用,然后评估 SQL 字符串(糟糕!)。
  • 破解它。首先添加一个虚拟方法:
  • 1
        public static object Invoke(string udfName, object[] arguments) { return null; }

    只要您使用 UserDefinedFunctionProvider.Invoke,请在您的 lambda 表达式中使用此方法。实现一个 ExpressionVisitor 替换所有出现的 MethodCallExpression mce ,其中 mce.Method 匹配虚拟方法 by

    1
    Expression.Call(null, udfMethod, mce.Arguments[0], mce.Arguments[1])

    其中 udfMethod

    1
    2
    3
    MethodInfo udfMethod = typeof(CosmosClient).Assembly
                    .GetType("Microsoft.Azure.Cosmos.Linq.UserDefinedFunctionProvider", throwOnError: true)
                    .GetMethod("Invoke", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);

    WhereSelect 等中使用生成的表达式。

    (添加单元测试以检查何时修复了错误并且可以删除黑客。)