EntityFramework Explicit Loading doesn't fetch all entities
I have 2 classes (User and Device) as described below.
public class User {
public int UserId { get; set; }
public virtual ICollection<Device> Devices { get; set; }
...
}
public class Device {
public int UserId;
public virtual User User { get; set; }
...
}
I have a repository for each of these two objects and I have disabled lazy loading in my data context like so.
public class MyDbContext : DbContext
{
public MyDbContext()
: base(name=MyDbContext)
{
this.Configuration.LazyLoadingEnabled = false;
}
}
I am trying to find all devices associated with a user account.
I tried to do it in two different ways.
Approach # 1 - Calling a Load on a User-Associated Property
using (MyDbContext dbContext = new MyDbContext())
{
// performing some database operations ...
var user = dbContext.Users.Find(8);
// do some operations
if (user.Devices == null or user.Devices.Count() ==0)
dbContext.Entry(user).Collection(u => u.Devices).Load();
var devices = user.Devices;
}
Approach # 2 - Removing from a set of devices using where
using (MyDbContext dbContext = new MyDbContext())
{
// performing some database operations ...
var user = dbContext.Users.Find(8);
// do some operations
if (user.Devices == null or user.Devices.Count() ==0)
var devices = dbContext.Devices.Where(d => d.UserId == user.UserId).ToList();
}
For some reason, Approach # 1 does not always retrieve all devices, however Approach # 2 retrieves all devices! Can someone please explain to me what I am doing wrong?
I started a SQL Server Profiler to see if I was doing something wrong. The queries generated by both approaches were identical. So I am really confused about what I am doing wrong!
source to share
Can someone explain to me what I am doing wrong?
I cannot explain why you are experiencing what you are experiencing, but personally I do not use Find()
and Load()
as these methods are complex in terms of how they work with the local context cache. Therefore, I would recommend the following query:
var user = dbContext.Users
.Include(u => u.Devices);
.FirstOrDefault(u => u.id = 8);
Since you're only fetching one user, no Cartesian issue . This request will populate the context with the user and all devices associated with the user in a single expression.
If you really want a separate variable with all devices afterwards:
var devices = user.Devices;
An important note about my answer is that since I am generally with Entity Framework in a web environment, my code is constantly creating / deleting context, so a local cache on the Entity Framework is pretty much useless. For a stateless application (Winforms / WPF) this might not be the best solution.
Updated for your comment
Is there another way to download later?
Like Brendan Green Comment you can use:
var devices = dbContext.Devices
.Where(w => w.UserId == 8);
(Note that this does not execute the query against the data source).
source to share