Warm tip: This article is reproduced from serverfault.com, please click

Getting a System.NotSupportedException when using MongoDB.Driver.Linq

发布于 2020-11-28 19:58:47

I am using MongoDB for my database and I am using ASP.NET Core for my api. I am trying to convert my Items object to a ItemsDTO (Data Transfer Object), because I don't want to return the Id. However, when I use

_items.AsQueryable()
.Where(item => item.Game.Contains("Games/1"))
.Select(item => ItemToDTO(item))
.ToList();

It gives back a System.NotSupportedException: 'ItemToDTO of type Project.Services.ItemService is not supported in the expression tree ItemToDTO({document}).' By the way ItemToDTO looks like this:

private static ItemDTO ItemToDTO(Item item)
        {
            return new ItemDTO
            {
                Name = item.Name,
                Type = item.Type,
                Price = item.Price,
                Game = item.Game,
                CostToSell = item.CostToSell,
                Description = item.Description
            };
        }

So I am confused on why this doesn't work because before I was using a SQL Server Database and normal Linq that looked like this:

_context.Items
.Where(item => item.Game.Contains("Games/1"))
.Select(item => ItemToDTO(item))
.ToList(),

and it worked the data that I wanted. I know that when using the MongoDB.Driver I am using their Linq and Queryable objects. Just wondering why I am getting the error above.

Questioner
Christian Moore
Viewed
0
Svyatoslav Danyliv 2020-11-29 17:23:39

It is typical mistake when working with LINQ. Translator can not look into ItemToDTO function body and will materialize whole item and then call ItemToDTO to correct result. Probably it is not a way for MongoDb and bad way for relational databases.

So I propose rewrite your function and create extension:

public static IQueryable<ItemDTO> ItemToDTO(this IQueryable<Item> items)
{
   return items.Select(item => new ItemDTO
   {
       Name = item.Name,
       Type = item.Type,
       Price = item.Price,
       Game = item.Game,
       CostToSell = item.CostToSell,
       Description = item.Description
   });
}

Then your query should work fine:

_context.Items
   .Where(item => item.Game.Contains("Games/1"))
   .ItemToDTO()
   .ToList()