Home > Software design >  How to return FirstOrDefaultAsync EF Linq to entity List query
How to return FirstOrDefaultAsync EF Linq to entity List query

Time:11-09

I have this Linq to entity query that returns a list of visitors with joins.
I want a similar query to return a single record without the query being a List collection, but changing it to a basic select with FirstOrDefaultAsync gets the error "A query body must end with a select clause or a group clause"

public async Task<List<VisitorDetail>> GetOneVisitor(int visitorId)
{
    var query = await (from v in _context.Visitors
        where v.Id == visitorId
        join d in _context.Categories on v.VisitCategoryId equals d.Id
        join c in _context.Counters on v.AssignedCounter equals c.Host into counterGroup
        from cg in counterGroup.DefaultIfEmpty()
        select new
        {
            FirstName = v.FirstName,
            LastName = v.LastName,
            CounterDescription = cg.Description,
            VisitCategory = d.Description
        }).ToListAsync();

    List<VisitorDetail> visitors = new();

    foreach (var p in query)
    {
        visitors.Add(new VisitorDetail
        {
            FirstName = p.FirstName,
            LastName = p.LastName,
            CounterDescription = p.CounterDescription,
            CategoryDescription = p.VisitCategory
        });
    }
    return visitors;
}

CodePudding user response:

If you want to keep DRY with LINQ to Entities, return IQueryable for your common queries and invoke materialization only when it is needed.

Your method can be rewritten in the following way:

public IQueryable<VisitorDetail> GetVisitorDetails(int visitorId)
{
    var query = 
        from v in _context.Visitors
        where v.Id == visitorId
        join d in _context.Categories on v.VisitCategoryId equals d.Id
        join c in _context.Counters on v.AssignedCounter equals c.Host into counterGroup
        from cg in counterGroup.DefaultIfEmpty()
        select new VisitorDetail
        {
            FirstName = v.FirstName,
            LastName = v.LastName,
            CounterDescription = cg.Description,
            CategoryDescription = d.Description
        };

    return query;
}
var many = await GetVisitorDetails(visitorId).ToListAsync();
var one  = await GetVisitorDetails(visitorId).FirstOrDefaultAsync();
  • Related