I have tried to research why, what I believe should be a relatively straightforward concept, is not working as expected. From what I have read the following should work in the way I expect, but it isn't.
I am retrieving data from an SQL database using entity framework, however I cannot get Lazy / Deferred loading to work when accessing child objects.
Here is my class
public class Product
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string ShortDescription { get; set; }
public string FullDescription { get; set; }
public virtual IList<ProductEvent> Events { get; set; } = new List<ProductEvent>();
}
I then assign a variable to a Product
var product = ServiceController.ProductService.GetProduct(123456);
and the GetProduct method:
public Product GetProduct(int id, params Expression<Func<Product, object>>[] includedProperties)
{
IQueryable<Product> products = _db.Products;
if (includedProperties != null)
{
foreach (var includeProperty in includedProperties)
{
products = products.Include(includeProperty);
}
}
return products.Single(p => p.Id == id);
}
The generated SQL includes a WHERE clause when I call the method and pass in a Product ID, as expected. So far, so good.
My problem arises when I try to access a sub-set of Events which are related to this Product:
var desiredEvent = product.Events.SingleOrDefault(e => e.StartDateTime == '2017-07-01T02:00');
I would expect the generated SQL to contain a WHERE clause to only return Events with a matching StartDateTime, however the SQL does not contain any WHERE clause so all Product Events are loaded into memory and filtered there. Some of my Products have over 100,000 events so this is causing performance issues.
I cannot understand what is wrong with the code which is causing my filter to be ignored when Events are accessed.
Am I missing something fundamental here with the way EF handles queries? Or is the way I am accessing the Product in the first place causing the problem?