I need to return list of requests entity from my data access layer. Please note that requests entity internally has a collection of products. Products entity also has collection of sizes and colors as shown below.
I used all joins at the top as I am forcing EF Core to use inner joins in my output SQL. That is why I have gone for query syntax for LINQ rather than method syntax (lambda) of LINQ.
If I try to fetch data using navigation properties EF Core generates left joins which I don't want. My requirement is to select all the requests if it has products and if product has sizes and colors. So I need all inner joins in my query.
My requirement is to map list of products and its sizes and colors to each request id. I am not able to do this. Please see the below method that I have been trying.
public class Requests
{
public int RequestId { get; set; }
public string Status { get; set; }
public DateTime OrderDate { get; set; }
public DateTime? ShippingDate { get; set; }
public int CreatedUser { get; set; }
public DateTime CreatedDate { get; set; }
public Customer Customer { get; set; }
public ICollection<Products> Products { get; set; }
}
public class Products
{
public int ProductId { get; set; }
public int RequestId { get; set; }
public string Sku { get; set; }
public string ItemName{ get; set; }
public Requests Request { get; set; }
public ICollection<ProductSizes> Sizes { get; set; }
public ICollection<ProductColors> Colors { get; set; }
}
public IQueryable<Requests> SearchRequests(InputFile inputFile)
{
var Requests = from requests in _context.Requests
join customer in _contex.Customer on requests.Requestid equals customer.Requestid
join items in _context.Products on requests.Requestid equals products.Requestid
join sizes in _context.ProductSizes on items.Productid equals sizes.Productid
join colors in _context.ProductColors on items.Productid equals colors.Productid
where customer.id == inputFile.id
&& requests.Status == 'Final'
&& sizes.Size == inputFile.Size
select new Requests
{
Requestid = requests.Requestid,
Status = requests.Status,
OrderDate = requests.OrderDate,
ShippingDate = requests.ShippingDate,
CreatedUser = requests.CreatedUser
Customer = customer
Items = new List<Products>
{
new Items
{
Requestid = requests.Id,
ProductId = items.ProductId,
sku= items.sku,
ItemName = items.ItemName,
Sizes= new List<ProductSizes> {sizes},
Colors = new List<ProuctColors> {colors}
}
}
};
return sourceRequests;
}
In the business layer, I am then doing the manual modelling (assignment of products to its own RequestId) as shown here:
Requests.ForEach(req =>
{
req.Products = Requests.SelectMany(p => p.Products)
.Where(sp => sp.RequestId == req.RequestId)
.GroupBy(prd => prd.ProductId)
.Select(prd => prd.First()).ToList();
req.Products.ToList().ForEach(prd => prd.productSizes =
Requests.SelectMany(prd => prd.Products)
.Where(x => x.ProductId == prd.ProductId).ToList()
.SelectMany(y => y.ProductSizes).Distinct().ToList()
);
req.Products.ToList().ForEach(prd => prd.productColors =
Requests.SelectMany(prd => prd.Products)
.Where(x => x.ProductId == prd.ProductId).ToList()
.SelectMany(y => y.ProductColors).Distinct().ToList()
);
});
Problem
I want to avoid this step in business layer and want to do the modeling in the data layer itself. But, I am not able to populate child collection (Products of its own request id. If I use navigation property from Requests entity to populate Products, EF Core is automatically mapping products to its own Request ID. But it would generate a left join between Requests and Products table which I don't want. I want to use inner join between Requests and Products table and do the data modelling in data layer itself (populate Products of its own request id and sizes and colors nested collections specific to the Product Id and RequestId)