#linq #azure-cosmosdb
#linq #azure-cosmosdb
Вопрос:
В документации по переводу LINQ в SQL для Cosmos DB говорится:
Определяемая пользователем функция расширения функции: поддерживает перевод из метода заглушки UserDefinedFunctionProvider.Вызов соответствующей пользовательской функции.
Однако эта функция не является общедоступной в .NET SDK v3 (хотя она есть в версии v2). Итак, каков обходной путь, пока ошибка не будет исправлена?
Ответ №1:
Существует несколько обходных путей:
- Не используйте LINQ.
- Используйте LINQ, но без вызова UDFS, затем получите строку запроса с помощью
query.ToQueryDefinition.QueryText
и манипулируйте ею, чтобы вставить вызовы UDF в нужные вам места, а затем оценить строку SQL (фу!). - Взломайте его. Сначала добавьте фиктивный метод:
public static object Invoke(string udfName, object[] arguments) { return null; }
Используйте этот метод в своих лямбда-выражениях всякий раз, когда вы бы использовали в противном случае UserDefinedFunctionProvider.Invoke
. Внедрите, ExpressionVisitor
который заменяет все вхождения, MethodCallExpression mce
где mce.Method
соответствует фиктивному методу, на
Expression.Call(null, udfMethod, mce.Arguments[0], mce.Arguments[1])
где udfMethod
находится
MethodInfo udfMethod = typeof(CosmosClient).Assembly
.GetType("Microsoft.Azure.Cosmos.Linq.UserDefinedFunctionProvider", throwOnError: true)
.GetMethod("Invoke", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
Используйте полученное выражение в вашем Where
, Select
и т.д.
(Добавьте модульный тест, чтобы проверить, когда ошибка была исправлена и хак может быть удален.)
Ответ №2:
Я использую Microsoft.Azure.Cosmos 3.22.1 SDK для моего примера с UDF (определяемыми пользователем функциями), и он отлично работал.
Я использовал пример от Microsoft.
Конечно, также возможно использовать UDF в сочетании с предложениями where.
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));
}