MongoFramework icon indicating copy to clipboard operation
MongoFramework copied to clipboard

Custom LINQ Provider

Open Turnerj opened this issue 4 years ago • 3 comments

While #54 talks about replacing the entire driver, this is a more focused change on replacing the entire LINQ pipeline of the driver with a custom implementation.

The main benefit is extensibility of queries and potentially generation of more optimal queries. This project is still a huge undertaking but is one independent step towards a better library.

Thoughts:

  • Have some type of mapping service between the IQueryable extension methods and the actual functions that will help generate that part of the stage.
  • Have this mapper be able to be updated at runtime by passing in the function you want mapped and the class capable of mapping the value to some intermediate type
  • Like the driver, certain commands that appear after each other (like two or more Where calls) need to be merged together.
  • Would entirely eliminate the reflection methods used to support the BsonDocument pre-stage stuff etc
  • Would allow more generic support for things like $geoNear etc
  • Optimising away the ResultTransformer, allowing better queries (eg. .Any()) to be translated more directly

The hardest thing in the whole build of this is all the sub-query bits, things like complex Where or Select statements.

Turnerj avatar Jul 09 '19 09:07 Turnerj

It would also be really cool to add support for explain on the query. This could be taken even a step further suggesting the ideal way to query that data (commands, indexes etc).

Turnerj avatar Jul 09 '19 09:07 Turnerj

As I suspected, it should be fairly straight forward to build the outer stages and having them configurable at runtime via a custom query converter. The harder bit is definitely parsing the internal lambda expressions.

Things it needs to consider:

  • Handling constants (effectively, they need to be written to the output BsonDocument)
  • Handling nested queries
  • Handling calls to certain property types (eg. MyDate.Date)
  • Handling nested method calls in general (there might be a nice way I can allow that to help build the query with the same general infrastructure)

Other changes required:

Turnerj avatar Nov 05 '19 03:11 Turnerj

Basic benchmark of the current LINQ query generation. Some surprises but overall, not fantastic.

BenchmarkDotNet=v0.12.1, OS=Windows 10.0.18362.1082 (1903/May2019Update/19H1)
Intel Core i7-6700HQ CPU 2.60GHz (Skylake), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=5.0.100-rc.1.20452.10
  [Host]        : .NET Core 3.0.1 (CoreCLR 4.700.19.51502, CoreFX 4.700.19.51609), X64 RyuJIT
  .NET Core 3.0 : .NET Core 3.0.1 (CoreCLR 4.700.19.51502, CoreFX 4.700.19.51609), X64 RyuJIT

Job=.NET Core 3.0  Runtime=.NET Core 3.0
Method Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
FirstOrDefault 775.0 us 5.83 us 5.46 us 19.5313 - - 62.21 KB
ToArray 784.4 us 14.69 us 16.32 us 15.6250 - - 49.95 KB
Count 1,021.1 us 13.37 us 12.51 us 23.4375 - - 72.99 KB
Any 1,010.0 us 14.41 us 12.78 us 23.4375 - - 72.82 KB

Turnerj avatar Sep 20 '20 13:09 Turnerj