首页 > 解决方案 > 如何在 Mongo.Net 驱动程序中链接 FilterDefinitionBuilders

问题描述

我有一个过滤器,我想将它添加到我的每个查询中,作为我要在数据库上执行的任何查询的基础。这将意味着我不必记得添加过滤器(filter.Eq("deleted", false) & filter.Eq("another query", null)在我对我的收藏进行的每次调用中。

在过去使用其他流畅的接口时,我假设我们可以简单地通过构建器来添加我喜欢的尽可能多的过滤器,直到我真正准备好执行查询,然后我会调用一个.Build()命令,这最终会给我我的FilterDefinition对象。

但是,当我尝试组合Eq()调用时,它会立即转换为 a FilterDefinition,而不是在FilterDefinitionBuilder时机成熟之前将其保留为 a。这在 Mongo 看来似乎是不可扩展且目光短浅的,因为添加.Build()功能可以让您以更灵活的方式链接命令。

首先,是否有任何理由决定以这种方式进行。我想了解为什么会这样,因为我知道人们不会随意做出这些决定。

其次,是否有人设法编写任何扩展方法来帮助我解决他们不介意分享的当前困境。

我的第一次尝试是包含以下内容:

public static FilterDefinitionBuilder<TDocument>(this FilterDefinitionBuilder<TDocument> filter)
{
    var name = GetCollectionName<TDocument>();
    return filter.Eq("deleted", false);
}

然后我会从我将使用的包装函数调用它,而不是调用静态Builders<CosmosDocumentType>.Filter函数,我会调用一个实用函数来包装它并返回一个FilterDefinitionBuilder我可以添加更多过滤器的对象。

一旦完成,我想调用一个.Build()方法,然后呈现一个相当可爱且相当实用的FilterDefinition对象,它将从集合中获取我想要的文档。

这样做.Build()还可以让我查询集合中所有未删除的文档,而无需添加更多过滤器,因为目前这似乎是在 aFilterDefinitionBuilder和 a之间转换的唯一方法FilterDefinition

另一种选择是围绕功能编写我自己的 Fluent 包装器,并FilterDefinitionBuilder在我对所有过滤器都到位时感到满意时在最后运行它。

如果有一种方法可以将现有的过滤器拉出来,FilterDefinition那也可能会有所帮助。

标签: c#mongodbmongodb-.net-driver

解决方案


据我了解,您需要使用基本过滤器来装饰所有过滤器。您可以使用各种方法进行,我在下面列出了三种。

假设您的基本过滤器具有以下内容:

var builder = Builders<BsonDocument>.Filter;
var baseFilter = builder.Eq("deleted", false) & 
                 builder.Eq("another query", BsonNull.Value);

以及您需要装饰的以下过滤器:

var filter01 = Builders<BsonDocument>.Filter.Eq("value", 1);
var filter02 = Builders<BsonDocument>.Filter.Eq("value", 2);

然后:

  1. 我们可以有一个高阶装饰器函数,它接受一个基本过滤器并返回一个函数,该函数在其他过滤器上的应用将产生一个将用基本过滤器装饰的过滤器。

它的实现很简单,如下:

public static Func<FilterDefinition<T>, FilterDefinition<T>>
  DecoratedFilter<T>(FilterDefinition<T> baseFilter) =>
    filter => baseFilter & filter;

您现在可以使用该DecoratedFilter()函数来获取一个函数并在您的过滤器上使用它,如下所示:

var decorate = DecoratedFilter(baseFilter);

var decoratedFilter01 = decorate(filter01);
var decoratedFilter02 = decorate(filter02);
  1. 另一种方法是让您自己拥有一个扩展方法:
public static FilterDefinition<T>
  Decorate<T>(this FilterDefinition<T> firstFilter,
              FilterDefinition<T> secondFilter) => 
    firstFilter & secondFilter;

它可以按如下方式使用:

var decoratedFilter01 = filter01.Decorate(baseFilter);
var decoratedFilter02 = filter02.Decorate(baseFilter);
  1. 您可以根据您的特定用例对基本过滤器进行硬编码,并且可以具有如下实现:
public static readonly FilterDefinition<BsonDocument> BaseFilter = ...

public static FilterDefinition<BsonDocument>
  WithBaseFilter(this FilterDefinition<BsonDocument> filter) =>
    BaseFilter & filter;

然后只需将其用作:

var decoratedFilter01 = filter01.WithBaseFilter();
var decoratedFilter02 = filter02.WithBaseFilter();

推荐阅读