我在 Cosmos DocumentDB 中有一个集合,我们在其中引入了一个名为
CustomParams
的字段。它是Dictionary<string, object>
的序列化形式。这个想法是为了适应从一个文档到另一个文档不同的任何类型的自定义值。这个设计不是我能掌控的,无法更改。
我们的 api 有一个查询端点,它构建一个表达式树(谓词)并针对该容器运行它以生成结果。现在要求添加到查询中(过滤
Dictionary<string, object>
中的特定日期字段)。问题是,由于该值是一个对象,我尝试使用 DateTime.Parse(customParams[key]!.ToString())
将其转换为 DateTime 并将其与传递到我们的 api 中的日期时间进行比较,但是 Cosmos 不高兴,并在我尝试时给出了 Microsoft.Azure.Cosmos.Linq.DocumentQueryException: Method 'Parse' is not supported.
将其添加到表达式树中。
我改变了我的方法,并尝试将它们作为谓词中的字符串
customParams[key]!.ToString() == request.TargetDate.ToString()
进行比较 - 虽然 cosmos 对此感到满意,但它没有返回所需的结果,因为 DateString 转换的对象生成的日期字符串不是与请求生成的日期字符串相同 - 而且感觉像是一个容易出错的 hack。
所以我不得不求助于从表达式树中取出这个逻辑,而是保留旧的表达式树来生成结果(我们将其转换为 IReadOnlyCollection),然后对集合进行后处理。
简而言之,这是我必须从表达式树中取出并在集合上作为后处理运行的代码片段:
private static bool DoesTargetDateMatch(OrderItem orderItem, IOrderedPagedQuery request)
{
return request.TargetDate != null &&
orderItem.CustomParams != null &&
orderItem.CustomParams.TryGetValue("Target Date", out var targetDate) &&
targetDate != null &&
DateOnly.FromDateTime(DateTime.Parse(targetDate.ToString()!)) == DateOnly.FromDateTime(request.TargetDate!.Value);
}
是否有办法在谓词本身中容纳这一点,这不会让人感觉很麻烦并且完全避免了后处理?
我认为您应该重构查询以使用
is
运算符。
选项1:
private static bool DoesTargetDateMatch(OrderItem orderItem, IOrderedPagedQuery request)
{
if (request.TargetDate > DateTime.MinValue && request.TargetDate < DateTime.MaxValue)
{
//targetdate is valid
//now check with CustomParams
if (orderItem.CustomParams.TryGetValue("Target Date", out object d) && d is DateTime)
{
return (DateTime)d == request.TargetDate;
}
}
return false;
}
选项2:
private static bool DoesTargetDateMatch(OrderItem orderItem, IOrderedPagedQuery request)
{
if (request.TargetDate is DateTime)
{
//targetdate is valid
//now check with CustomParams
if (orderItem.CustomParams.TryGetValue("Target Date", out object d) && d is DateTime)
{
return (DateTime)d == request.TargetDate;
}
}
return false;
}