gpt4 book ai didi

linq - LINQ to CosmosDB 中数组的交集

转载 作者:行者123 更新时间:2023-12-01 23:08:16 29 4
gpt4 key购买 nike

我正在尝试查找数据库中的所有项目,这些项目在数组中至少有一个值与我在代码中拥有的数组中的任何值相匹配(两个数组的交集不应为空)。

基本上,我正在努力实现这一目标:

public List<Book> ListBooks(string partitionKey, List<string> categories)
{
return _client.CreateDocumentQuery<Book>(GetCollectionUri(), new FeedOptions
{
PartitionKey = new PartitionKey(partitionKey)
})
.Where(b => b.Categories.Any(c => categories.Contains(c))
.ToList();
}

Book 类如下所示:

public class Book
{
public string id {get;set;}
public string Title {get;set;}
public string AuthorName {get;set;}
public List<string> Categories {get;set;}
}

但是,执行此代码时,SDK 会抛出异常,表示不支持方法“Any”。这也不起作用:

return _client.CreateDocumentQuery<Book>(GetCollectionUri(), new FeedOptions
{
PartitionKey = new PartitionKey(partitionKey)
})
.Where(b => categories.Any(c => b.Categories.Contains(c))
.ToList();

以下代码有效,因为只有一个类别可供查找:

public List<Book> ListBooksAsync(string category)
{
return _client.CreateDocumentQuery<Book>(GetCollectionUri())
.Where(b => b.Categories.Contains(category))
.ToList();
}

在普通 SQL 中,我可以将多个 ARRAY_CONTAINS 与多个 OR 一起排队,查询将正确执行。

SELECT * FROM root 
WHERE ARRAY_CONTAINS(root["Categories"], 'Humor')
OR ARRAY_CONTAINS(root["Categories"], 'Fantasy')
OR ARRAY_CONTAINS(root["Categories"], 'Legend')

我正在尝试找到使用 LINQ 实现此目的的最佳方法,但我什至不确定这是否可行。

最佳答案

在这种情况下,我使用了一个辅助方法来组合表达式,其计算结果为 SQL,如最后一个示例中所示。下面的辅助方法“MakeOrExpression”允许您传递多个谓词(在您的情况下,单独检查 b.Categories.Contains(category))并生成一个表达式,您可以将其放入 .Where(expression) 的参数中文档查询。

class Program
{
private class Book
{
public string id { get; set; }
public string Title { get; set; }
public string AuthorName { get; set; }
public List<string> Categories { get; set; }
}

static void Main(string[] args)
{
var comparison = new[] { "a", "b", "c" };

var target = new Book[] {
new Book { id = "book1", Categories = new List<string> { "b", "z" } },
new Book { id = "book2", Categories = new List<string> { "s", "t" } },
new Book { id = "book3", Categories = new List<string> { "z", "a" } } };

var results = target.AsQueryable()
.Where(MakeOrExpression(comparison.Select(x => (Expression<Func<Book, bool>>)(y => y.Categories.Contains(x))).ToArray()));

foreach (var result in results)
{
// Should be book1 and book3
Console.WriteLine(result.id);
}

Console.ReadLine();
}

private static Expression<Func<T,bool>> MakeOrExpression<T>(params Expression<Func<T,bool>>[] inputExpressions)
{
var combinedExpression = inputExpressions.Skip(1).Aggregate(
inputExpressions[0].Body,
(agg, x) => Expression.OrElse(agg, x.Body));

var parameterExpression = Expression.Parameter(typeof(T));

var replaceParameterVisitor = new ReplaceParameterVisitor(parameterExpression,
Enumerable.SelectMany(inputExpressions, ((Expression<Func<T, bool>> x) => x.Parameters)));

var mergedExpression = replaceParameterVisitor.Visit(combinedExpression);

var result = Expression.Lambda<Func<T, bool>>(mergedExpression, parameterExpression);
return result;
}

private class ReplaceParameterVisitor : ExpressionVisitor
{
private readonly IEnumerable<ParameterExpression> targetParameterExpressions;
private readonly ParameterExpression parameterExpression;

public ReplaceParameterVisitor(ParameterExpression parameterExpressionParam, IEnumerable<ParameterExpression> targetParameterExpressionsParam)
{
this.parameterExpression = parameterExpressionParam;
this.targetParameterExpressions = targetParameterExpressionsParam;
}

public override Expression Visit(Expression node)
=> targetParameterExpressions.Contains(node) ? this.parameterExpression : base.Visit(node);
}
}

关于linq - LINQ to CosmosDB 中数组的交集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48870626/

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