Summary: What is the best practice when using the MongoDB Entity Framework provider to be able to modify the data returned by a query?
I tried the following LinQ select statement based on logic that had worked with other database providers. The .withoutPassword() method is a method on my User class to return a version of the user with the password field set to null.
This gets the exception MongoDB.Driver.Linq.ExpressionNotSupportedException: 'Expression not supported: u.withoutPassword().'.
I read the following…
Select Projections
Select projections use the Select() method in a LINQ query to change the structure of the created object. The projection changes the object by performing groupings, or selecting fields into anonymous types or alternative types not recognized by Entity Framework.
This version of the EF Core Provider does not support Select Projections.
What is the best practice for performing the equivalent functionality of a select projection when using this provider?
The best option here would be to put a ToList before the Select so that the operation can happen client side.
We have scheduled work to much improve the select projection experience for the next sprint which will hopefully also enable the scenario you showed as-is without need for the extra ToList step.
We are just wrapping up Queryable Encryption and Vector Search right now and then the next ticket we’re intending to tackle is anonymous projections which would enable these scenarios.
Unfortunately don’t have a specific timeline on it yet.
You might be able to get what you want working on it right now as we did make some minor improvements in the mean time - failing that you can always put a ToList before the Select projection to enable that part to happen client-side.
The best practice is to project the data into a DTO (Data Transfer Object) using LINQ before materializing it (e.g., with .ToList() or .FirstOrDefault()). This keeps your data transformation logic separate from your EF models and avoids unintended side effects on tracked entities. Example:
var result = context.Users
.Select(u => new UserDto {
Id = u.Id,
Name = u.Name.ToUpper() // Modify here
})
.ToList();
This approach ensures clean separation of concerns and better performance.
You can do _context.Users.ToList().Select(user => user.withoutPassword()).ToListAsync() but I suspect you’re trying to avoid it ever coming into memory - although having a password unencrypted in a data store is a whole other problem.
There isn’t any one-size-fits-all “best-practice” for selecting data and adding layers and DTOs just-in-case is a code smell.
You can avoid unintended side effects and gain a performance boost by just putting .AsNoTracking() on the end of a query.
Part of the whole push for Code First and POCOs in the EF 4 era was to avoid having to project rich entities into DTOs. Quite often (but not always) now the entities are the DTOs.