Uploaded image for project: 'C# Driver'
  1. C# Driver
  2. CSHARP-2113

Expression based queries don't work for properties on nested interface types

    • Type: Icon: Bug Bug
    • Resolution: Fixed
    • Priority: Icon: Major - P3 Major - P3
    • 2.19.0
    • Affects Version/s: None
    • Component/s: LINQ3

      When using the expression based query API against a property on a (nested) interface type the driver fails with an exception. The below code demonstrates the issue:

      using System;
      using System.Linq.Expressions;
      using FluentAssertions;
      using MongoDB.Bson;
      using MongoDB.Bson.Serialization;
      using MongoDB.Driver.Linq.Translators;
      using Xunit;
      
      namespace MongoDB.Driver.Tests.Linq.Translators
      {
          public class InterfaceTranslatorTests
          {
              #region Failing scenario
              public interface IMakeTheTestFail
              {
                  int I { get; set; }
              }
      
              public class FailingType : IMakeTheTestFail
              {
                  public IMakeTheTestFail Inner { get; set; }
                  public int I { get; set; }
              }
      
              [Fact]
              public void Fails()
              {
                  Assert(
                      (IMakeTheTestFail x) => x.I == 1,
                      "{'I': 1}");
                  Assert(
                      (FailingType x) => x.Inner.I == 1,
                      "{'Inner.I': 1}");
              }
              #endregion
      
              #region Working scenario
              public class WorkingType
              {
                  public WorkingType Inner { get; set; }
                  public int I { get; set; }
              }
      
              [Fact]
              public void Works()
              {
                  Assert(
                      (WorkingType x) => x.I == 1,
                      "{'I': 1}");
                  Assert(
                      (WorkingType x) => x.Inner.I == 1,
                      "{'Inner.I': 1}");
              }
              #endregion
      
              public void Assert<T>(Expression<Func<T, bool>> filter, string expectedFilter)
              {
                  var serializer = BsonSerializer.SerializerRegistry.GetSerializer<T>();
                  var filterDocument = PredicateTranslator.Translate(filter, serializer, BsonSerializer.SerializerRegistry);
      
                  filterDocument.Should().Be(BsonDocument.Parse(expectedFilter));
              }
          }
      }
      

      It all comes down to the fact that the nested property "Inner" will be automatically assigned a serializer of type DiscriminatedInterfaceSerializer which does not implement IBsonDocumentSerializer which again is fair enough since it shouldn't really know about the concretes mappings for properties on an unknown implementor of its covered interface... However, for querying purposes it would appear desirable to have that functionality in place.

      The problem starts when SerializationBinder.VisitMember(MemberExpression node) performs the following type check:

                          var documentSerializer = serializationExpression.Serializer as IBsonDocumentSerializer;
                          BsonSerializationInfo memberSerializationInfo;
                          if (documentSerializer != null && documentSerializer.TryGetMemberSerializationInfo(node.Member.Name, out memberSerializationInfo))
      
      

      As a result of this check, in the above example, this will cause the filter expression to be translated into "{(

      {document}.I == 1)}" as opposed to "{({document}

      .*{I}* == 1)}" for the working case which again causes PredicateTranslator.GetFieldExpression(Expression expression) to not find a matching field and fail:

      System.InvalidOperationException
      {document}{Inner}.I is not supported.
         at MongoDB.Driver.Linq.Translators.PredicateTranslator.GetFieldExpression(Expression expression) in C:\Users\daniel.hegener\Source\Repos\mongo-csharp-driver2\src\MongoDB.Driver\Linq\Translators\PredicateTranslator.cs:line 1637
      

            Assignee:
            robert@mongodb.com Robert Stam
            Reporter:
            daniel.hegener@gmx.net Daniel Hegener
            Votes:
            1 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: