IMongoCollection 当我传入Func的谓词时会抛出一个

问题描述 投票:1回答:1

我正在尝试对ASP.NET Core Web控制器进行单元测试。这是朴素的数据访问的样子:

var database = configuration.GetSection("MongoDb:Database").Value;
var mongoSettings = new MongoCollectionSettings() { AssignIdOnInsert = true };
var users = client.GetDatabase(database).GetCollection<User>("User", mongoSettings);
var user = users.Find(u => u.EmailAddress == emailAddress).SingleOrDefault();

这很好。它不容易进行单元测试(Find无法通过Moq进行模拟),我更喜欢在数据访问上使用间接层,因此我尝试将其重构为这样的存储库类:

public interface IRepository<T>
{
    T SingleOrDefault(Func<T, bool> predicate);
}


public class MongoRepository<T> : IRepository<T>
{
    // ...
    public T SingleOrDefault(Func<T, bool> predicate)
    {
        var objects = client.GetDatabase(this.databaseName).GetCollection<T>(this.repositoryName, this.settings);
        var toReturn = objects.Find(o => predicate(o) == true).SingleOrDefault();
        return toReturn;
    }
}

当我更新控制器以使用MongoRepository<User>时,它抛出:

var usersRepo = new MongoRepository<User>(this.configuration, this.client);
var user = usersRepo.SingleOrDefault(u => u.EmailAddress == emailAddress);

具体来说,在存储库代码中,objects.Find(o => predicate(o) == true).SingleOrDefault();引发异常:An exception of type 'System.InvalidOperationException' occurred in MongoDB.Driver.dll but was not handled in user code: 'Invoke(value(System.Func 2 [AutoDungeoners.Web.Models.User,System.Boolean]),{document})不支持。'`

我不确定该如何解决。我怀疑谓词Func<T, bool>的定义不正确,因为如果我仅调用objects.Find(o => true),它将返回第一个对象而没有任何问题。

下面是完整的异常堆栈。

An exception of type 'System.InvalidOperationException' occurred in MongoDB.Driver.dll but was not handled in user code: 'Invoke(value(System.Func`2[AutoDungeoners.Web.Models.User,System.Boolean]), {document}) is not supported.'
   at MongoDB.Driver.Linq.Translators.PredicateTranslator.GetFieldExpression(Expression expression)
   at MongoDB.Driver.Linq.Translators.PredicateTranslator.TranslateComparison(Expression variableExpression, ExpressionType operatorType, ConstantExpression constantExpression)
   at MongoDB.Driver.Linq.Translators.PredicateTranslator.TranslateComparison(BinaryExpression binaryExpression)
   at MongoDB.Driver.Linq.Translators.PredicateTranslator.Translate(Expression node)
   at MongoDB.Driver.Linq.Translators.PredicateTranslator.Translate(Expression node, IBsonSerializerRegistry serializerRegistry)
   at MongoDB.Driver.Linq.Translators.PredicateTranslator.Translate[TDocument](Expression`1 predicate, IBsonSerializer`1 parameterSerializer, IBsonSerializerRegistry serializerRegistry)
   at MongoDB.Driver.ExpressionFilterDefinition`1.Render(IBsonSerializer`1 documentSerializer, IBsonSerializerRegistry serializerRegistry)
   at MongoDB.Driver.MongoCollectionImpl`1.CreateFindOperation[TProjection](FilterDefinition`1 filter, FindOptions`2 options)
   at MongoDB.Driver.MongoCollectionImpl`1.FindSync[TProjection](IClientSessionHandle session, FilterDefinition`1 filter, FindOptions`2 options, CancellationToken cancellationToken)
   at MongoDB.Driver.MongoCollectionImpl`1.<>c__DisplayClass41_0`1.<FindSync>b__0(IClientSessionHandle session)
   at MongoDB.Driver.MongoCollectionImpl`1.UsingImplicitSession[TResult](Func`2 func, CancellationToken cancellationToken)
   at MongoDB.Driver.MongoCollectionImpl`1.FindSync[TProjection](FilterDefinition`1 filter, FindOptions`2 options, CancellationToken cancellationToken)
   at MongoDB.Driver.FindFluent`2.ToCursor(CancellationToken cancellationToken)
   at MongoDB.Driver.IAsyncCursorSourceExtensions.SingleOrDefault[TDocument](IAsyncCursorSource`1 source, CancellationToken cancellationToken)
   at MongoDB.Driver.IFindFluentExtensions.SingleOrDefault[TDocument,TProjection](IFindFluent`2 find, CancellationToken cancellationToken)

c# mongodb asp.net-core mongodb-.net-driver
1个回答
0
投票

您可以在此处使用的Find(...)方法的唯一实现是(docs)

public static IFindFluent<TDocument, TDocument> Find<TDocument>(this IMongoCollection<TDocument> collection, Expression<Func<TDocument, bool>> filter, FindOptions options = null)

FuncExpression<Func>之间的差异描述为here。基本上,GetCollection返回对Mongodb集合的引用,这里的Find方法的作用是将expression tree转换为MongoDB查询。在数据库中执行查询的时刻是调用SingleOrDefault()的时刻,这是您将获得异常的地方。

由于Func<T,bool>Expression<Func<T,bool>>之间没有隐式转换,因此您尝试使用o => predicate(o) == true创建另一个表达式并使代码可编译,但如上所述-MongoDB .NET驱动程序将无法弄清楚如何翻译此类内容表达式进入MongoDB查询。

您需要将实现更改为:

public T SingleOrDefault(Expression<Func<T, bool>> predicate)
{
    var objects = client.GetDatabase(this.databaseName).GetCollection<T>(this.repositoryName, this.settings);
    var toReturn = objects.Find(o => predicate(o) == true).SingleOrDefault();
    return toReturn;
}

并且请记住,这仅适用于可以转换为MongoDB查询语言的表达式。 u => u.EmailAddress == emailAddress看起来不错。

© www.soinside.com 2019 - 2024. All rights reserved.