1
votes

I am working on a ASP.NET Core Web API project and I want the controllers return results asynchronously. But I am having problems with the get by id call.

Models:

public class Product
{
    [Key]
    public int Id { get; set; }

    [Required]
    public string ProductType { get; set; }

    [Required]
    [MaxLength(250)]
    public string ProductDescription { get; set; }

    [Required]
    public int ProductCategory { get; set; }

    //Navigation Properties
    public int TravelPackageId { get; set; }
    public TravelPackage TravelPackage { get; set; }
}

public class TravelPackage
{
    [Key]
    public int Id { get; set; }

    [Required]
    [MaxLength(50)]
    public string PackageName { get; set; }

    //Navigation Properties
    public List<Product> Products { get; set; }
}

TravelPackage has a list of products. When I make a call to a travelPackage by id, I need that list of products be returned too.

This is my repository for both call (all travelPackages and specific travelPackage by id)

public class TravelPackageRepository : ITravelPackageRepository
{
    private readonly DataContext _context;

    public TravelPackageRepository(DataContext context)
    {
        _context = context;
    }

    public async Task<TravelPackage> GetProductByIdAsync(int id)
    {
        return await _context.TravelPackages.Include(t => t.Products.Select(p => new
        {
            Id = t.Id,
            PackageName = t.PackageName,
            Products = t.Products.Select(product => new Product()
            {
                Id = product.Id,
                ProductType = product.ProductType,
                ProductDescription = product.ProductDescription,
                ProductCategory = product.ProductCategory,
                TravelPackageId = product.TravelPackageId
            })
        })).FirstAsync(t => t.Id == id);
     
    }

    public async Task<System.Collections.Generic.IReadOnlyList<TravelPackage>> GetTravelPackagesAsync()
    {
        return await _context.TravelPackages
            .Include(x => x.Products)
            .ThenInclude(x => x.TravelPackage)
            .ToListAsync();
    }
}

But I am getting the following error:

System.InvalidOperationException: The expression 't.Products.AsQueryable().Select(p => new <>f__AnonymousType2`3(Id = t.Id, PackageName = t.PackageName, Products = t.Products.AsQueryable().Select(product => new Product() { Id = product.Id, ProductType = product.ProductType, ProductDescription = product.ProductDescription, ProductCategory = product.ProductCategory, TravelPackageId = product.TravelPackageId})))' is invalid inside an 'Include' operation, since it does not represent a property access: 't => t.MyProperty'. To target navigations declared on derived types, use casting ('t => ((Derived)t).MyProperty') or the 'as' operator ('t => (t as Derived).MyProperty'). Collection navigation access can be filtered by composing Where, OrderBy(Descending), ThenBy(Descending), Skip or Take operations.

Before implementing the repository and async/await, this was my controller for travelPackages and it worked fine:

[HttpGet("{id}")]
public  ActionResult<TravelPackage> GetTravelPackage(int id)
{
        var item = _context.TravelPackages.Where(package => package.Id == id).Select(package => new
        {
            Id= package.Id,
            PackageName =package.PackageName,
            Products = package.Products.Select(product => new Product()
            {
                Id = product.Id,
                ProductType = product.ProductType,
                ProductDescription = product.ProductDescription,
                ProductCategory = product.ProductCategory,
                TravelPackageId = product.TravelPackageId
            })
        });

        return Ok(item);
}

I do not have much experience working with .net core, async/await tasks and linq, so I am not sure how to deal with this error.

Thanks

2
How are you calling the new respository GetProductByIdAsync from controller?nbokmans

2 Answers

3
votes

As JMP noticed there is a syntax error. But also you are trying to return an anonymous object. So try this:

 return await _context.TravelPackages
    .Where(package => package.Id == id)
    .Select(t => 
     new TravelPackage
        {
            Id = t.Id,
            PackageName = t.PackageName,
            Products = t.Products.Select(product => new Product()
            {
                Id = product.Id,
                ProductType = product.ProductType,
                ProductDescription = product.ProductDescription,
                ProductCategory = product.ProductCategory,
                TravelPackageId = product.TravelPackageId
            })
        }).FirstOrDefaultAsync();

but since you are including all properties, you can make it shorter:

return await _context.TravelPackages
    .Include(t => t.Products)
    .Where(package => package.Id == id)
    .FirstOrDefaultAsync();
4
votes

The error is caused by this:

_context.TravelPackages.Include(t => t.Products.Select

The Include statement should represent a property access but you are selecting to an anonymous object within the Include.

In this case, the navigation property is Products so change it to:

_context.TravelPackages.Include(t => t.Products).Select

This has a closing bracket after the Products navigation property. So you are then including Product and the select query follows this.