C
C#•3y ago
Utsuhoagie

LINQ expression could not be translated after converting object

public static BugDTO ConvertToDTO(Bug bug) => new BugDTO
{
Id = bug.Id,
Description = bug.Description,
IsFixed = bug.IsFixed
};

// GET: api/Bugs
// api/Bugs?isFixed={true|false}
[HttpGet]
public async Task<ActionResult<IEnumerable<Bug /* BugDTO */>>> GetBugs([FromQuery] bool? isFixed)
{
// var allBugDTO = _context.Bugs.Select(bug => ConvertToDTO(bug));
var allBugDTO = _context.Bugs.Select(bug => bug);

if (isFixed == null)
{
var allBugDTOList = await allBugDTO.ToListAsync();
return allBugDTOList;
}

var filteredBugDTOList = await allBugDTO.Where(bug => bug.IsFixed == isFixed!).ToListAsync();
return filteredBugDTOList;
}
public static BugDTO ConvertToDTO(Bug bug) => new BugDTO
{
Id = bug.Id,
Description = bug.Description,
IsFixed = bug.IsFixed
};

// GET: api/Bugs
// api/Bugs?isFixed={true|false}
[HttpGet]
public async Task<ActionResult<IEnumerable<Bug /* BugDTO */>>> GetBugs([FromQuery] bool? isFixed)
{
// var allBugDTO = _context.Bugs.Select(bug => ConvertToDTO(bug));
var allBugDTO = _context.Bugs.Select(bug => bug);

if (isFixed == null)
{
var allBugDTOList = await allBugDTO.ToListAsync();
return allBugDTOList;
}

var filteredBugDTOList = await allBugDTO.Where(bug => bug.IsFixed == isFixed!).ToListAsync();
return filteredBugDTOList;
}
Why am I getting this error when I try to convert an object to another very similar object? This is in ASP.NET with Web API scaffolding, in my BugController.cs class. Bug and BugDTO are almost identical classes, except Bug has an extra property. If I run the code below, it works just fine. But if I change the return type from ...<Bug>... with ...<BugDTO>..., and change the lambda expr in _context.Bugs.Select(...) to also convert the Bugs to BugDTOs, then the error in the screenshot happens. I originally thought it was due to isFixed being nullable, but forgiving null doesn't change anything. The error message also shows my lambda expr as b => (bool?)BugsController... which could be a problem, but I don't know what. Both allBugDTOList and filteredBugDTOList are of type List<BugDTO> as well, assuming I made the DTO-related changes in my 2nd paragraph. Any help's appreciated, I'm still very new to C#
8 Replies
canton7
canton7•3y ago
You're asking the database to construct BugDTO objects, and it's complaining that it doesn't know how to. You'll have to fetch the Bug objects from the database into memory first (e.g. with ToListAsync), and then do the mapping So .ToListAsync().Select(...) not .Select(...).ToListAsync() The problem there of course is that you're filtering after you've converted to BugDTO objects, which means you'll dowload everything from the database, construct BugDTO objects for each one, and only then do the filtering. You'd be much better off doing the filtering on the Bug objects
public async Task<ActionResult<IEnumerable<BugDTO>>> GetBugs([FromQuery] bool? isFixed)
{
var bugs = _context.Bugs;

if (isFixed != null)
{
bugs = bugs.Where(bug => bug.IsFixed == isFixed.Value);
}

return (await bugs.ToListAsync()).Select(bug => ConvertToDTO(bug));
}
public async Task<ActionResult<IEnumerable<BugDTO>>> GetBugs([FromQuery] bool? isFixed)
{
var bugs = _context.Bugs;

if (isFixed != null)
{
bugs = bugs.Where(bug => bug.IsFixed == isFixed.Value);
}

return (await bugs.ToListAsync()).Select(bug => ConvertToDTO(bug));
}
Utsuhoagie
UtsuhoagieOP•3y ago
Thanks! This worked, though I'm not too concerned about performance right now. What I'm wondering is how my initial _context.Bugs.Select(bug => ConvertToDTO(bug)) still works, if isFixed is null and the .Where query isn't run, which is why I initially thought the problem was with my .Where query and not my .Select (thinking rn, I'm still confused, late replies)
canton7
canton7•3y ago
Maybe it's smart enough to see just a Select that it can't translate, and move that to after it's fetched the data from the database. But if you throw in the Where as well it doesn't want to move that after it's fetched the data, as that means fetching the entire table, and it can't re-order the Select and Where, so it has to give up
Unknown User
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
Utsuhoagie
UtsuhoagieOP•3y ago
Okay so I think what I'm being confused about is: how is this line IQueryable<BugDTO> bugDTOs = bugs.Select(bug => ConvertToDTO(bug)) still working, if I just don't query .Where on bugDTOs afterwards (added some types for clarity) Is it because the .Select returns a different type, only after it has queried the DB, so the BugDTO type not existing in the DB not cause a problem? And if I call another query, which is now on an IQueryable<BugDTO> rather than the usual IQueryable<Bug>, and since BugDTO does not exist in the DB, it only causes an error now? Thanks! I haven't seen these keywords so far, I'll need to read up on this
canton7
canton7•3y ago
I think it must be EF being helpful, and silently moving that logic until after the fetch, because it can. @walticotc 's article might give a proper answer though Ah yes, in the very first and second sections 😛
Utsuhoagie
UtsuhoagieOP•3y ago
Wow, that is literally my issue. Can't get better help than that! Thanks to both of you for the help
Unknown User
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
Want results from more Discord servers?
Add your server