【问题标题】:MongoDB c# driver: Case Insensitive Compare using in or contains on a list using linqMongoDB c#驱动程序:不区分大小写比较使用in或包含在使用linq的列表中
【发布时间】:2020-06-01 09:46:41
【问题描述】:

我正在使用 MongoDB C# 驱动程序,我想对集合执行 linq where 子句,将属性的小写版本与我在内存中的列表的小写版本进行比较。像这样;

items = items.Where(i => listToCheck.Contains(i.Property.ToLower()));

我也试过了……

items = items.Where(i => i.Property.ToLower().In(listToCheck));

我认为这实际上是正确的,应该可以工作,但可能尚未实施。

我收到一条错误消息,提示与 ToLower() 命令相关的“不支持 where 子句”。据我所知,驱动程序目前无法完成此操作,因为它必须使用 Regex 进行“IN”查询,而我认为这是不可能的。

我想知道是否可以,如果可以,怎么做?

【问题讨论】:

  • 你试过了吗:items = items.Where(i => listToCheck.Any(item => item.ToLower() == i.Property.ToLower()));
  • 我刚试了一下,没用。我收到此错误...'无法确定表达式的序列化信息:String[]:{ "one", "two" }'
  • 项目是否可查询?可能是你需要做 items.AsQueryable()

标签: c# linq mongodb


【解决方案1】:

我最终找到了解决这个问题的方法,经过大量挖掘,我发现 toLower() 方法没有在 mongoDb linq 提供程序中实现,所以我不得不改用 MongoQuery

我为字符串和列表创建了一些扩展方法,它将字符串或列表作为源并将其转换为 bson 正则表达式

internal static List<BsonValue> ConvertToCaseInsensitiveRegexList(this IEnumerable<string> source)
{
    return source.Select(range => new BsonRegularExpression("/^" + range.Replace("+", @"\+") + "$/i")).Cast<BsonValue>().ToList();
}

internal static List<BsonValue> ConvertToEndsWithRegexList(this IEnumerable<string> source)
{
    return source.Select(range => new BsonRegularExpression("/" + range.Replace("+", @"\+") + "$/i")).Cast<BsonValue>().ToList();
}

internal static BsonRegularExpression ToCaseInsensitiveRegex(this string source)
{
    return new BsonRegularExpression("/^" + source.Replace("+", @"\+") + "$/i");
}

然后他们就这样使用了……

var colours = new List<string> { "Red", "blue", "white" };
var query = Query<myObject>.In(v => v.Colour, colours.ConvertToCaseInsensitiveRegexList());
this.Find(query).ToList();

【讨论】:

【解决方案2】:

我遇到了同样的问题,不得不从几个不同的 SO 答案中拼凑出一个解决方案,包括这个。

我已经在解决方案中随处使用 IQueryable 以及存储库模式,所以我真的不想退回到使用 .Find()

我的解决方案是使用三参数 .In() 重载扩展过滤器定义构建器,这将提供不区分大小写的功能。然后,我使用.Where(_ =&gt; filter.Inject()) 将过滤器添加到查询中,同时仍将其保持为 IQueryable。

扩展名:

public static class MongoExtensions
{
    public static FilterDefinition<TDocument> In<TDocument>(
        this FilterDefinitionBuilder<TDocument> builder,
        Expression<Func<TDocument, object>> expr,
        IEnumerable<string> values,
        bool ignoreCase)
    {
        if (!ignoreCase)
        {
            return builder.In(expr, values);
        }

        var filters = values
            .Select(v => builder.Regex(expr, new BsonRegularExpression($"^{Regex.Escape(v)}$", "i")));

        return builder.Or(filters);
    }
}

使用问题中的原始代码,它看起来像:

var filter = Builders<MyCollection>.Filter.In(i => i.Property, listToCheck, true);
items = items.Where(_ => filter.Inject());

【讨论】:

    猜你喜欢
    • 2023-04-02
    • 1970-01-01
    • 2015-01-22
    • 2012-01-03
    • 2011-04-20
    • 2011-08-09
    • 1970-01-01
    • 2013-06-29
    • 2012-10-06
    相关资源
    最近更新 更多