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

Support Expression.MakeIndex in LINQ3

    • Type: Icon: New Feature New Feature
    • Resolution: Done
    • Priority: Icon: Unknown Unknown
    • 2.21.0
    • Affects Version/s: None
    • Component/s: None
    • None
    • Not Needed
    • Hide

      1. What would you like to communicate to the user about this feature?
      2. Would you like the user to see examples of the syntax and/or executable code and its output?
      3. Which versions of the driver/connector does this apply to?

      Show
      1. What would you like to communicate to the user about this feature? 2. Would you like the user to see examples of the syntax and/or executable code and its output? 3. Which versions of the driver/connector does this apply to?

      Summary

      By manually constructing Dictionary indexes with `Expression` class in Linq, I can't access dictionary keys with MongoDB LinqV3.

      MongoDB.Driver.Linq.ExpressionNotSupportedException: Expression not supported: it.Fields.Item["DynamicField1{_}{_}"].

      MongoDB Driver: 2.19.0

      How to Reproduce

      ```

      public class SampleDocument

      {

          public string Id { get; set; }

          [BsonDictionaryOptions(DictionaryRepresentation.Document)]
          public required IDictionary<string, object?> Fields { get; set; }

      }

       

      public class SampleRepository

      {

          private readonly IMongoCollection<SampleDocument> _sampleDocumentCollection;

        public async ValueTask LoadSampleDocuments(
              CancellationToken cancellationToken = default)
          {
              var baseQuery = _sampleDocumentCollection
                  .AsQueryable();

              if (true) {

                  __            

                  var searchableFields = new[] { "DynamicField1", "DynamicField2" };

                  var parameter = Expression.Parameter(typeof(SampleDocument), "it");

                  var dictType = typeof(IDictionary<string, object>);
                  var dictionaryIndexer = dictType.GetProperty("Item")!;

                  var expressions = searchableFields
                      .Select(Expression.Equal(
                              Expression.MakeIndex(
                                  Expression.Property(parameter, nameof(PolicyMemberStateDocument.Fields)),
                                  dictionaryIndexer,
                                  new List<Expression> { Expression.Constant(fieldPath) }),
                              Expression.Constant("SearchValue")))
                      .ToList();
                  var dynamicFilter = expressions[0];

                  if (expressions.Count > 1)
                  {
                      foreach (var expression in expressions.GetRange(1, expressions.Count - 1))
                     

      {                     dynamicFilter = Expression.Or(dynamicFilter, expression);                 }

                  }

                  var lambda = Expression.Lambda<Func<PolicyMemberStateDocument, bool>>(
                      dynamicFilter,
                      parameter);
                  baseQuery = baseQuery.Where(lambda);

              }

             var result = await baseQuery.ToListAsync(cancellationToken);

      }

      ```

      Additional Background

      Code in .NET repo that makes it `it.Fields.Item["DynamicField1"]` instead of `it.Fields["DynamicField1"]` : ExpressionStringBuilder.cs (microsoft.com)

      I am building dynamic filtering for LinqV3 and encountered this issue for dynamic fields.

      Stack trace:

      MongoDB.Driver.Linq.ExpressionNotSupportedException: Expression not supported: it.Fields.Item["DynamicField1"].
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.ExpressionToAggregationExpressionTranslator.Translate(TranslationContext context, Expression expression)
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.BinaryExpressionToAggregationExpressionTranslator.Translate(TranslationContext context, BinaryExpression expression)
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.ExpressionToAggregationExpressionTranslator.Translate(TranslationContext context, Expression expression)
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.BinaryExpressionToAggregationExpressionTranslator.Translate(TranslationContext context, BinaryExpression expression)
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.ExpressionToAggregationExpressionTranslator.Translate(TranslationContext context, Expression expression)
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToFilterTranslators.ExpressionToFilterTranslator.TranslateUsingAggregationOperators(TranslationContext context, Expression expression)
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToFilterTranslators.ExpressionToFilterTranslator.Translate(TranslationContext context, Expression expression, Boolean exprOk)
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToFilterTranslators.ExpressionToFilterTranslator.TranslateLambda(TranslationContext context, LambdaExpression lambdaExpression, IBsonSerializer parameterSerializer, Boolean asRoot)
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToPipelineTranslators.WhereMethodToPipelineTranslator.Translate(TranslationContext context, MethodCallExpression expression)
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToPipelineTranslators.ExpressionToPipelineTranslator.Translate(TranslationContext context, Expression expression)
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToPipelineTranslators.OrderByMethodToPipelineTranslator.Translate(TranslationContext context, MethodCallExpression expression)
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToPipelineTranslators.ExpressionToPipelineTranslator.Translate(TranslationContext context, Expression expression)
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToPipelineTranslators.GroupByMethodToPipelineTranslator.Translate(TranslationContext context, MethodCallExpression expression)
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToPipelineTranslators.ExpressionToPipelineTranslator.Translate(TranslationContext context, Expression expression)
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToPipelineTranslators.SelectMethodToPipelineTranslator.Translate(TranslationContext context, MethodCallExpression expression)
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToPipelineTranslators.ExpressionToPipelineTranslator.Translate(TranslationContext context, Expression expression)
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToPipelineTranslators.WhereMethodToPipelineTranslator.Translate(TranslationContext context, MethodCallExpression expression)
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToPipelineTranslators.ExpressionToPipelineTranslator.Translate(TranslationContext context, Expression expression)
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToPipelineTranslators.OrderByMethodToPipelineTranslator.Translate(TranslationContext context, MethodCallExpression expression)
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToPipelineTranslators.ExpressionToPipelineTranslator.Translate(TranslationContext context, Expression expression)
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToPipelineTranslators.SkipMethodToPipelineTranslator.Translate(TranslationContext context, MethodCallExpression expression)
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToPipelineTranslators.ExpressionToPipelineTranslator.Translate(TranslationContext context, Expression expression)
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToPipelineTranslators.TakeMethodToPipelineTranslator.Translate(TranslationContext context, MethodCallExpression expression)
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToPipelineTranslators.ExpressionToPipelineTranslator.Translate(TranslationContext context, Expression expression)
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToExecutableQueryTranslators.ExpressionToExecutableQueryTranslator.Translate[TDocument,TOutput](MongoQueryProvider`1 provider, Expression expression)
         at MongoDB.Driver.Linq.Linq3Implementation.MongoQuery`2.ToCursorAsync(CancellationToken cancellationToken)
         at MongoDB.Driver.IAsyncCursorSourceExtensions.ToListAsync[TDocument](IAsyncCursorSource`1 source, CancellationToken cancellationToken) 

            Assignee:
            robert@mongodb.com Robert Stam
            Reporter:
            SpaierInstinct@gmail.com Pavel Levchuk
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: