I have object CartItem and Product.
I need to make one List<> from these 2 objects.
Tried:
List<(CartItem,Product)> product = new List<(CartItem,Product)>();
Code:
public async Task<IActionResult> Index()
{
var username = User.Identity.Name;
if (username == null)
{
return Login();
}
var user = _context.Users.FirstOrDefault(x => x.Email == username);
List<CartItem> cart = _context.ShoppingCartItems.Where(s => s.IDuser.Equals(user.Id)).ToList();
List<Product> product = new List<Product>();
foreach (var item in cart)
{
product.Add(_context.Product.FirstOrDefault(x => x.id == item.ProductId));
}
return View(user);
}
3
Answers
You can make a struct and put both variables in there:
then you can create a list of that struct:
The correct answer would be to not do that. What would be the expected result for 5 items and 2 products?
The code is loading both CartItem and Product objects from the database using loops. That’s very slow as each object requires yet another query. This can be replaced with a single line producing a single SQL query.
If
CartItem
hasProduct
andUser
properties (as it should) all the code can be replaced with :EF Core will generate the SQL query that joins User, CartItem, Product together and returns items and their products, but no
User
data. TheProduct
data will be available through theCartItem.Product
propertyWhat was asked but shouldn’t be used
If a
List<(CartItem,Product)>
is absolutely required (why???) you could use that instead of aList<Product>
, and add items inside the loop:This will result in one extra SQL query per cart item.
Slightly better
A slightly better option would be to generate a
WHERE product.ID IN (....)
clause, to load all relevant products in a single query. After that the two lists would have to be joined with JOIN.This will reduce the N+1 queries to 2. It’s still slower than letting the database do the work though
First, see the answer of @Panagiotis Kanavos. Aside that, for combining part, you can do this: