[CSHARP-2197] MongoDB Linq Query failing with embedded document interface Created: 16/Feb/18  Updated: 09/Nov/22

Status: Backlog
Project: C# Driver
Component/s: LINQ3
Affects Version/s: 2.4.4, 2.5
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Pedro Góes Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: triaged
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Windows OS / .NET Core and .NET Framework projects


Issue Links:
Duplicate
Case:

 Description   

Original Post: https://stackoverflow.com/questions/48470510/c-sharp-mongodb-linq-query-failing-with-embedded-document-interface

I'm trying to use LINQ expressions to query a simple collection in MongoDB but currently I'm facing issues when the root document contains an embedded document represented by an interface in the C# model. This is happening for me at the current MonboDB C# 2.5.0 Driver.

I've put together an example which reproduces my problem. If I have a pair of classes defined as such:

public class MainClass
{
    [BsonId]
    public Guid Id { get; set; }
    public String Name { get; set; }
    public InnerClass Child { get; set; }
}
 
public class InnerClass
{
    public String Name { get; set; }
}

I can query it with no problems with the following Linq query:

var entity = collection.AsQueryable<MainClass>().SingleOrDefault(x => x.Child.Name.Equals("Some Value"));

However, if I change my model to the following (basically replacing straight class references with interfaces):

public class MainClass : IMainClass
{
    [BsonId]
    public Guid Id { get; set; }
    public String Name { get; set; }
    public IInnerClass Child { get; set; }
}
 
public class InnerClass : IInnerClass
{
    public String Name { get; set; }
}
 
public interface IMainClass
{
    Guid Id { get; set; }
    String Name { get; set; }
    IInnerClass Child { get; set; }
}
 
public interface IInnerClass
{
    String Name { get; set; }
}

When performing the same query I get the following exception:

System.InvalidOperationException: '{document}.Child.Name is not supported.'

Both examples work just fine when queried with standard mongodb queries (either with interface or concrete class in the generic signature):

var entity = collection.Find(Builders<IMainClass>.Filter.Eq("Child.Name", "Some Value")).SingleOrDefault();

Debugging around MongoDB C# Driver source code, the problem seems to happen somewhere around the PredicateTranslator class when it tries:

TryGetFieldExpression(expression, out fieldExpression)
For some reason, in the failing example, the Expression node arrives with a type of "System.Linq.Expressions.PropertyExpression" which fails to cast to "MongoDB.Driver.Linq.Expressions.IFieldExpression". Meanwhile, the in the working example the Expression node arrives with a type of "MongoDB.Driver.Linq.Expressions.FieldExpression" which, of course, casts just fine to "MongoDB.Driver.Linq.Expressions.IFieldExpression".

I was also able to verify that in both examples the expression trees arrive the same at the driver but their structure start to differ at the PipelineBinder stage.

In the end, my question is: Is this supposed to work? Is the document modeled wrong in the first place? Any suggestions on how to get this to work?



 Comments   
Comment by James Kovacs [ 09/Nov/22 ]

using System;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
 
var client = new MongoClient();
var db = client.GetDatabase("test");
var coll = db.GetCollection<MainClass>("coll");
 
var filter = Builders<MainClass>.Filter.Eq("Child.Name", "Some Value");
var find = coll.Find(filter);
Console.WriteLine(find);  // works
 
var query = coll.AsQueryable().Where(x => x.Child.Name == "Some Value");
Console.WriteLine(query); // throws
 
public class MainClass
{
    public int Id { get; set; }
    public IInnerClass Child { get; set; }
}
 
public class InnerClass : IInnerClass
{
    public string Name { get; set; }
}
 
public interface IInnerClass
{
    string Name { get; set; }
}

Fluent Find works but LINQ3 throws the following exception:

System.NotSupportedException: Serializer for IInnerClass must implement IBsonDocumentSerializer to be used with LINQ.
   at MongoDB.Driver.Linq.Linq3Implementation.Misc.DocumentSerializerHelper.GetFieldInfo(IBsonSerializer serializer, String memberName) in /Users/james/Dropbox/code/mongodb/mongo-csharp-driver/src/MongoDB.Driver/Linq/Linq3Implementation/Misc/DocumentSerializerHelper.cs:line 27
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.MemberExpressionToAggregationExpressionTranslator.Translate(TranslationContext context, MemberExpression expression) in /Users/james/Dropbox/code/mongodb/mongo-csharp-driver/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MemberExpressionToAggregationExpressionTranslator.cs:line 74
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.ExpressionToAggregationExpressionTranslator.Translate(TranslationContext context, Expression expression) in /Users/james/Dropbox/code/mongodb/mongo-csharp-driver/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/ExpressionToAggregationExpressionTranslator.cs:line 67
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.BinaryExpressionToAggregationExpressionTranslator.Translate(TranslationContext context, BinaryExpression expression) in /Users/james/Dropbox/code/mongodb/mongo-csharp-driver/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/BinaryExpressionToAggregationExpressionTranslator.cs:line 49
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.ExpressionToAggregationExpressionTranslator.Translate(TranslationContext context, Expression expression) in /Users/james/Dropbox/code/mongodb/mongo-csharp-driver/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/ExpressionToAggregationExpressionTranslator.cs:line 54
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToFilterTranslators.ExpressionToFilterTranslator.TranslateUsingAggregationOperators(TranslationContext context, Expression expression) in /Users/james/Dropbox/code/mongodb/mongo-csharp-driver/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionToFilterTranslator.cs:line 75
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToFilterTranslators.ExpressionToFilterTranslator.Translate(TranslationContext context, Expression expression, Boolean exprOk) in /Users/james/Dropbox/code/mongodb/mongo-csharp-driver/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionToFilterTranslator.cs:line 40
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToFilterTranslators.ExpressionToFilterTranslator.TranslateLambda(TranslationContext context, LambdaExpression lambdaExpression, IBsonSerializer parameterSerializer, Boolean asRoot) in /Users/james/Dropbox/code/mongodb/mongo-csharp-driver/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionToFilterTranslator.cs:line 69
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToPipelineTranslators.WhereMethodToPipelineTranslator.Translate(TranslationContext context, MethodCallExpression expression) in /Users/james/Dropbox/code/mongodb/mongo-csharp-driver/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/WhereMethodToPipelineTranslator.cs:line 39
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToPipelineTranslators.ExpressionToPipelineTranslator.Translate(TranslationContext context, Expression expression) in /Users/james/Dropbox/code/mongodb/mongo-csharp-driver/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/ExpressionToPipelineTranslator.cs:line 67
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToExecutableQueryTranslators.ExpressionToExecutableQueryTranslator.Translate[TDocument,TOutput](MongoQueryProvider`1 provider, Expression expression) in /Users/james/Dropbox/code/mongodb/mongo-csharp-driver/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/ExpressionToExecutableQueryTranslator.cs:line 34
   at MongoDB.Driver.Linq.Linq3Implementation.MongoQuery`2.ToString() in /Users/james/Dropbox/code/mongodb/mongo-csharp-driver/src/MongoDB.Driver/Linq/Linq3Implementation/MongoQuery.cs:line 106

Generated at Wed Feb 07 21:41:52 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.