diff --git a/src/MongoDB.Driver/Linq/IMongoQueryProvider.cs b/src/MongoDB.Driver/Linq/IMongoQueryProvider.cs
index 6f26855d2be..d51a2686eff 100644
--- a/src/MongoDB.Driver/Linq/IMongoQueryProvider.cs
+++ b/src/MongoDB.Driver/Linq/IMongoQueryProvider.cs
@@ -40,6 +40,15 @@ public interface IMongoQueryProvider : IQueryProvider
/// The cancellation token.
/// The value that results from executing the specified query.
Task ExecuteAsync(Expression expression, CancellationToken cancellationToken = default(CancellationToken));
+
+ ///
+ /// Translates an Expression to MQL.
+ ///
+ /// The expression.
+ /// The output serializer.
+ /// The type of the result.
+ /// An array of MQL pipeline stages represented as BsonDocuments.
+ BsonDocument[] Translate(Expression expression, out IBsonSerializer outputSerializer);
}
///
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/MongoQueryProvider.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/MongoQueryProvider.cs
index 2717a7e71d7..e411b2ac0c5 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/MongoQueryProvider.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/MongoQueryProvider.cs
@@ -55,6 +55,7 @@ protected MongoQueryProvider(
public abstract TResult Execute(Expression expression);
public abstract Task ExecuteAsync(Expression expression, CancellationToken cancellationToken);
public abstract ExpressionTranslationOptions GetTranslationOptions();
+ public abstract BsonDocument[] Translate(Expression expression, out IBsonSerializer outputSerializer);
}
internal sealed class MongoQueryProvider : MongoQueryProvider
@@ -152,5 +153,14 @@ public override ExpressionTranslationOptions GetTranslationOptions()
var database = _database ?? _collection?.Database;
return translationOptions.AddMissingOptionsFrom(database?.Client.Settings.TranslationOptions);
}
+
+ public override BsonDocument[] Translate(Expression expression, out IBsonSerializer outputSerializer)
+ {
+ var translationOptions = GetTranslationOptions();
+ var executableQuery = ExpressionToExecutableQueryTranslator.Translate(provider: this, expression, translationOptions);
+ var stages = executableQuery.Pipeline.Ast.Stages;
+ outputSerializer = (IBsonSerializer)executableQuery.Pipeline.OutputSerializer;
+ return stages.Select(s => s.Render().AsBsonDocument).ToArray();
+ }
}
}
diff --git a/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp5473Tests.cs b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp5473Tests.cs
new file mode 100644
index 00000000000..8cf20decca5
--- /dev/null
+++ b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp5473Tests.cs
@@ -0,0 +1,57 @@
+/* Copyright 2010-present MongoDB Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System.Linq;
+using FluentAssertions;
+using MongoDB.Driver.Linq;
+using Xunit;
+
+namespace MongoDB.Driver.Tests.Linq.Linq3Implementation.Jira
+{
+ public class CSharp5473Tests : Linq3IntegrationTest
+ {
+ [Fact]
+ public void Translate_expression_should_work()
+ {
+ var collection = GetCollection();
+ var queryable = collection.AsQueryable()
+ .Select(x => x.X + 1);
+ var expression = queryable.Expression; // queryable was just used as an easy way to create the expression and the provider
+ var provider = (IMongoQueryProvider)queryable.Provider;
+
+ var stages = provider.Translate(expression, out var outputSerializer);
+ AssertStages(stages, "{ $project : { _v : { $add : ['$X', 1] }, _id : 0 } }");
+
+ var pipeline = new BsonDocumentStagePipelineDefinition(stages, outputSerializer);
+ var result = collection.Aggregate(pipeline).Single();
+ result.Should().Be(2);
+ }
+
+ private IMongoCollection GetCollection()
+ {
+ var collection = GetCollection("test");
+ CreateCollection(
+ collection,
+ new C { Id = 1, X = 1 });
+ return collection;
+ }
+
+ private class C
+ {
+ public int Id { get; set; }
+ public int X { get; set; }
+ }
+ }
+}