ProjectToType with Mongodb Queryable
Is there any way to use the ProjectToType extension with IMongoQueryable of MongoDB c# driver? IMongoQueryable extends IQueryable.
I was solving a similar issue with AutoMaper. https://stackoverflow.com/a/66220779/4438653 You can cast the IQueryable back to IMongoQueryable.
var posts = db.GetCollection<Post>("posts");
var postList = await ((IMongoQueryable<PostDto>)posts.AsQueryable()
.ProjectToType<PostDto>())
.ToListAsync();
class Post
{
[BsonId]
public ObjectId Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
}
public record PostDto(string Title, string Description);
I tried that but got this exception
Unhandled exception. System.ArgumentNullException: Value cannot be null. (Parameter 'itemName')
at MongoDB.Driver.Core.Misc.Ensure.IsNotNull[T](T value, String paramName)
at MongoDB.Driver.Linq.Linq2Implementation.Expressions.SelectExpression..ctor(Expression source, String itemName, Expression selector)
at MongoDB.Driver.Linq.Linq2Implementation.Processors.Pipeline.MethodCallBinders.SelectBinder.Bind(PipelineExpression pipeline, PipelineBindingContext bindingContext, MethodCallExpression node, IEnumerable`1 arguments)
at MongoDB.Driver.Linq.Linq2Implementation.Processors.MethodInfoMethodCallBinder`1.Bind(PipelineExpression pipeline, TBindingContext bindingContext, MethodCallExpression node, IEnumerable`1 arguments)
at MongoDB.Driver.Linq.Linq2Implementation.Processors.PipelineBinderBase`1.BindMethodCall(MethodCallExpression node)
at MongoDB.Driver.Linq.Linq2Implementation.Processors.PipelineBinderBase`1.Bind(Expression node)
at MongoDB.Driver.Linq.Linq2Implementation.Processors.Pipeline.PipelineBinder.Bind(Expression node, IBsonSerializerRegistry serializerRegistry)
at MongoDB.Driver.Linq.Linq2Implementation.MongoQueryProviderImpl`1.Prepare(Expression expression)
at MongoDB.Driver.Linq.Linq2Implementation.MongoQueryProviderImpl`1.Translate(Expression expression)
at MongoDB.Driver.Linq.Linq2Implementation.MongoQueryProviderImpl`1.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
at MongoDB.Driver.Linq.Linq2Implementation.MongoQueryableImpl`2.ToCursorAsync(CancellationToken cancellationToken)
at MongoDB.Driver.IAsyncCursorSourceExtensions.ToListAsync[TDocument](IAsyncCursorSource`1 source, CancellationToken cancellationToken)
at Program.<Main>$(String[] args) in C:\Users\ziaul\\MapsterMongo\Program.cs:line 13
at Program.<Main>(String[] args)
This happened to me with automapper as well. What helped was writing the record in the old syntax with default constructor with no parameters.
public record PostDto
{
public string Title { get; init; }
public string Description { get; init; }
}
If that doesn't work for you, the last resort workaround could be that you can fetch your MongoDb entities into list. Then call Adpat and perform the mapping in memory and not in database,
This happened to me with automapper as well. What helped was writing the record in the old syntax with default constructor with no parameters.
doesn't help
Well, according to this: https://github.com/MapsterMapper/Mapster/issues/403. This project might not be maintained anymore. So in my opinion you have two options:
- Do mapping in memory
- Switch to another mapping tool e.g. AutoMapper
yeah you are correct. But I really like the way mapster does things. No need for di containers needed. Very simple mapping with extensions
Yes, it works very well with Entity Framework, however acts weird with MongoDb.
it would be very sad if it's not maintained anymore
@andrerav can you give something on it?
Hi @ziaulhasanhamim, I'm currently working on streamlining the build and packaging and get a new version of Mapster.Tool as soon as possible. After that I can take a closer look at this issue. I've read through this thread but not sure if I am understanding the problem correctly. Can you give me a clear explanation of what kind of functionality is missing in Mapster to help you with this problem?
Mapster supports mapping for queryable. I get a weird exception when I try to use mapster mapping with MongoDB queryable. MongoDB Queryable is very similar to ef core. Also I think automapper supports it without any extra dependency.
I think the issue is about parameter names in the expression that mapster creates to map one type to other.
Unhandled exception. System.ArgumentNullException: Value cannot be null. (Parameter 'itemName')
here the item name is the parameter name. MongoDB doesn't allow the parameter name to be null. It can be anything other than null.
I think this is how parameters are created in mapster expressions
Expression.Parameter(parameterType)
but there is also a second parameter which is parameterName.
Expression.Parameter(parameterType, parameterName)
This is my observation of the problem. It's very much possible that I'm wrong because I'm not that familiar with expression and queryable APIs.
But mapster can support MongoDB. I won't think there will be a lot of work.
I know there are many works pending but I just hope this project keeps up. This is literally the best mapper I've used in .net. Thanks to you for taking responsibility for this project
@andrerav Anything on this?
I'm using extension method:
public static IMongoQueryable<TResult> ProjectTo<TResult>(this IMongoQueryable query, TypeAdapterConfig config) { return (IMongoQueryable<TResult>)query.ProjectToType<TResult>(config); }
@Ryba1986 does't that thow exception? For me it throws an exception
I am using LinqProvider v3
Thank you sir appreciate your efforts. I was searching a solution for this for a lot of time.
@ziaulhasanhamim Using ProjectToType() with IQueryable can cause problems in cases where there are asynchronous operations. I suggest that you materialize your query (with ToList(), for example) before doing any mapping. This should fix your problem.
Hi
var posts = db.GetCollection<Post>("posts"); var postList = await ((IMongoQueryable<PostDto>)posts.AsQueryable() .ProjectToType<PostDto>()) .ToListAsync(); class Post { [BsonId] public ObjectId Id { get; set; } public string Title { get; set; } public string Description { get; set; } } public record PostDto(string Title, string Description);
I tried this code and it works correct if use MongoDb.Driver v2.19.0 and it gets exception in v2.18.0. I think it was bug of MongoDb.Driver
@Ryba1986 does't that thow exception? For me it throws an exception
I am using LinqProvider v3
I tried this code and it works correct if use MongoDb.Driver v2.19.0 and it gets exception in v2.18.0. I think it was bug of MongoDb.Driver
MongoDb.Driver before v2.19.0 using LinqProvider v2 for default.