Search code examples
lazy-loadingentity-framework-4.1ef-code-firstfluent-interface

Why my EF collection are not lazy?


I'm using EF 4.1 Code first. I have a model of user and a model of setting.
Each time the repository returns a user the Setting is also loaded. I've marked the Setting as virtual all my access modifiers are public LazyLoadingEnabled and ProxyCreationEnabled are enabled by default.
What am I missing?

public class User : BaseEntity
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public string Password { get; set; }
    public virtual ICollection<Setting> Settings { get; set; } 
}

public class Setting
{
    public int UserID { get; set; }
    public int SettingID { get; set; }
    public string Value { get; set; }
}

The User might have several setting, so there is a one to many relationship with a foreign key in setting.
The user configuration is

public class UserConfiguration : EntityTypeConfiguration<User>
{
    public UserConfiguration()
    {   
        HasKey(u => u.ID);
        HasMany(u => u.Settings).WithOptional().HasForeignKey(u => u.UserID);
    }
}

and the Setting configuration is:

 public class SettingsConfiguration : EntityTypeConfiguration<Setting>
{
    public SettingsConfiguration()
    {
        ToTable("UserSettings");
        HasKey(s => new { s.UserID, s.SettingID });
    }
}

Solution

  • Lazy loading means the opposite of what you think it means.

    • With lazy loading (virtual property and defaults)
      • Settings is not retrieved immediately when querying User
      • Settings is retrieved when it's accessed for the first time. The DbContext must be open at that time for this to happen; otherwise you'll get an exception
    • Without lazy loading (non-virtual property and/or explicitly disabled)
      • Settings is not retrieved immediately when querying User
      • Settings will never be retrieved automatically; it will return null (which, in my opinion, is a terrible design decision: null is a wrong value and you shouldn't be able to get it)

    In both cases, you can load Settings eagerly by using .Include(x => x.Settings), or when needed, by calling context.Entry(user).Collection(x => x.Settings).Load()