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

The LINQ3 provider does not support projection to a class taking a BsonDocument in its constructor

    • Type: Icon: Bug Bug
    • Resolution: Works as Designed
    • Priority: Icon: Unknown Unknown
    • None
    • Affects Version/s: 2.19.0
    • Component/s: LINQ3
    • None
    • None
    • 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?
    • None
    • None
    • None
    • None
    • None
    • None

      Summary

      The LINQ3 provider does not support projection to a class taking a BsonDocument in its constructor (the V2 provider supports it).

      How to Reproduce

      Linq3Bug.csproj
      <Project Sdk="Microsoft.NET.Sdk">
      
        <PropertyGroup>
          <OutputType>Exe</OutputType>
          <TargetFramework>net6.0</TargetFramework>
          <Nullable>enable</Nullable>
        </PropertyGroup>
      
        <ItemGroup>
          <PackageReference Include="EphemeralMongo6" Version="0.1.3" />
          <PackageReference Include="MongoDB.Driver" Version="2.19.0" />
        </ItemGroup>
      
      </Project>
      

       

      Program.cs
      using System;
      using System.Linq;
      using EphemeralMongo;
      using MongoDB.Bson;
      using MongoDB.Driver;
      using MongoDB.Driver.Linq;
      
      Console.Write("Running MongoDB");
      using var runner = MongoRunner.Run();
      Console.WriteLine($" on {runner.ConnectionString}");
      var settings = MongoClientSettings.FromConnectionString(runner.ConnectionString);
      if (Enum.TryParse<LinqProvider>(args.FirstOrDefault(), out var provider))
      {
          settings.LinqProvider = provider;
      }
      Console.WriteLine($"Using LinqProvider {settings.LinqProvider}");
      
      var client = new MongoClient(settings);
      var collection = client.GetDatabase("my-db").GetCollection<BsonDocument>("my-collection");
      var document = new BsonDocument
      {
          ["_id"] = ObjectId.GenerateNewId(),
          ["Name"] = "Me",
      };
      collection.InsertOne(document);
      var me = collection.Find(new BsonDocument()).Project(d => new Person(d)).Single();
      Console.WriteLine($"[{me.Id}] {me.Name}");
      
      public class Person
      {
          public Person(BsonDocument document)
          {
              Id = document["_id"].AsObjectId;
              Name = document["Name"].AsString;
          }
      
          public ObjectId Id { get; set; }
      
          public string Name { get; set; }
      }
      

      Run with the V2 driver (dotnet run V2): ✅ works as expected

      Unable to find source-code formatter for language: text. Available languages are: actionscript, ada, applescript, bash, c, c#, c++, cpp, css, erlang, go, groovy, haskell, html, java, javascript, js, json, lua, none, nyan, objc, perl, php, python, r, rainbow, ruby, scala, sh, sql, swift, visualbasic, xml, yaml
      Running MongoDB on mongodb://127.0.0.1:60766
      Using LinqProvider V2
      [63d846b35c677f6f0e813308] Me
      

      Run with the V3 driver (dotnet run V3): ❌ ExpressionNotSupportedException

      Unable to find source-code formatter for language: text. Available languages are: actionscript, ada, applescript, bash, c, c#, c++, cpp, css, erlang, go, groovy, haskell, html, java, javascript, js, json, lua, none, nyan, objc, perl, php, python, r, rainbow, ruby, scala, sh, sql, swift, visualbasic, xml, yaml
      Running MongoDB on mongodb://127.0.0.1:60866
      Using LinqProvider V3
      Unhandled exception. MongoDB.Driver.Linq.ExpressionNotSupportedException: Expression not supported: new Person(d) because constructor parameter document does not match any property.
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.NewExpressionToAggregationExpressionTranslator.GetMatchingPropertyName(NewExpression expression, String constructorParameterName)
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.NewExpressionToAggregationExpressionTranslator.<>c__DisplayClass0_0.<Translate>b__1(ParameterInfo p)
         at System.Linq.Enumerable.SelectArrayIterator`2.ToArray()
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.NewExpressionToAggregationExpressionTranslator.Translate(TranslationContext context, NewExpression expression)
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.ExpressionToAggregationExpressionTranslator.Translate(TranslationContext context, Expression expression)
         at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(TranslationContext context, LambdaExpression lambdaExpression, IBsonSerializer parameterSerializer, Boolean asRoot)
         at MongoDB.Driver.Linq.Linq3Implementation.LinqProviderAdapterV3.TranslateExpressionToProjection[TInput,TOutput](Expression`1 expression, IBsonSerializer`1 inputSerializer, IBsonSerializerRegistry serializerRegistry, ExpressionTranslationOptions translationOptions)
         at MongoDB.Driver.Linq.Linq3Implementation.LinqProviderAdapterV3.TranslateExpressionToFindProjection[TSource,TProjection](Expression`1 expression, IBsonSerializer`1 sourceSerializer, IBsonSerializerRegistry serializerRegistry)
         at MongoDB.Driver.FindExpressionProjectionDefinition`2.Render(IBsonSerializer`1 sourceSerializer, IBsonSerializerRegistry serializerRegistry, LinqProvider linqProvider)
         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__DisplayClass46_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.Single[TDocument](IAsyncCursorSource`1 source, CancellationToken cancellationToken)
         at MongoDB.Driver.IFindFluentExtensions.Single[TDocument,TProjection](IFindFluent`2 find, CancellationToken cancellationToken)
      

      Additional Background

      The Hangfire.Mongo project uses this pattern (Find + Project) a lot so it's impossible to migrate to the LINQ3 provider.

            Assignee:
            robert@mongodb.com Robert Stam
            Reporter:
            cedric.luthi@gmail.com Cédric Luthi
            Votes:
            1 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: