我试图在.Any()
子句中嵌套.Where()
,以查询本地CosmosDb模拟器。
代码如下所示;其中permittedStundentIds
是变量(List<long>
),a
是CosmosDb中的Document
.Where(a => permittedStudentIds.Any(sId => a.Students.Any(s => s.Id == sId)));
执行查询时,出现错误:
不支持方法“任何”。 ActivityId: 800000a8-0002-d600-b63f-84710c7967bb,documentdb-dotnet-sdk / 1.22.0 主机/ 64位MicrosoftWindowsNT / 10.0.16299.0
我尝试了多种变体来获得等效的表达式,但无济于事。唯一有效的方法是使用.Contains()
并对学生索引进行硬编码。这是不可行的,因为学生人数可能未知。
.Where(a => permittedStudentIds.Contains(a.Students[0].Id));
我确实知道CosmosDb的Sql API尚不支持某些lambda扩展,但是有解决方法吗?
答案 0 :(得分:2)
尝试了各种lambda表达式的多种组合之后,这对我有用。
我在DocumentModel
类中添加了OR-ed
属性;多余,但仅用于过滤。
此后,我使用.Contains()
Expression<Func<MyDocumentModel, bool>> query = a => a.StudentIds.Contains(permittedStudentIds[0]);
foreach (var id in permittedStudentIds.Skip(1))
{
query = query.Or(a => a.StudentIds.Contains(id));
}
进行查询,如下所示:
.Where(query);
,然后使用如下查询:
query.Or()
对于// See: https://blogs.msdn.microsoft.com/meek/2008/05/02/linq-to-entities-combining-predicates/
public static class ExpressionExtensions
{
public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
{
// build parameter map (from parameters of second to parameters of first)
var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);
// replace parameters in the second lambda expression with parameters from the first
var secondBody = ParameterVistor.ReplaceParameters(map, second.Body);
// apply composition of lambda expression bodies to parameters from the first expression
return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
}
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.AndAlso);
}
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.OrElse);
}
}
public class ParameterVistor : ExpressionVisitor
{
private readonly Dictionary<ParameterExpression, ParameterExpression> map;
public ParameterVistor(Dictionary<ParameterExpression, ParameterExpression> map)
{
this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
}
public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
{
return new ParameterVistor(map).Visit(exp);
}
protected override Expression VisitParameter(ParameterExpression p)
{
ParameterExpression replacement;
if (map.TryGetValue(p, out replacement))
{
p = replacement;
}
return base.VisitParameter(p);
}
}
部分,我使用了以下类:
ini_set("log_errors", TRUE);
ini_set("error_log", get_template_directory_uri() . "/errors.log");
答案 1 :(得分:0)
因此,您具有一系列的allowedStudentIds和具有一系列学生的文档。每个学生都有一个ID。
您想知道是否有任何允许的StudentId也是您文档中一个(或多个)学生的ID。
换句话说,如果allowedStudentIds的值为1、2,则您想知道文档中是否有任何Students.students的学生。
为什么不提取所有学生的ID,将其与您允许的学生ID相交,看看结果是否为空?
var studentIds = Document.Students.Select(student => student.Id);
var intersection = studentIds.Intersect(permittedStudentIds);
var result = intersection.Any();
// TODO: make one statement.
如果两个序列都是可查询的,则此方法有效,但是如果您的Document.Students是IQueryable且您的allowedStudentIds是IEnumerable,则也应适用。我最好的猜测是,这将成为SQL包含的内容。参见Queryable.Intersect