-
Type:
Bug
-
Resolution: Works as Designed
-
Priority:
Unknown
-
None
-
Affects Version/s: 2.19.0
-
Component/s: LINQ3
-
None
-
(copied to CRM)
-
None
-
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.