Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EF6 lazy loading doesn't work while eager loading works fine

I updated my app from EF4.1 to EF6 and now I've got lazy loading issue. I used EF6.x DbContext Generator to generate new DbContext. All of the advices from this article are also applied.

  • My classes are public
  • Not sealed, not abstract
  • Have a public constructor
  • Don't implement neither IEntityWithChangeTracker nor IEntityWithRelationships
  • Both ProxyCreationEnabled and LazyLoadingEnabled are set to true
  • Navigation properties are virtual

What also looks wierd to me is that if I explicitly include navigation property with Include("...") it gets loaded.

Simplified version of my POCOs and DbContext:

public partial class Ideation
{
    public Ideation()
    {

    }

    public long Id { get; set; }
    public Nullable<long> ChallengeId { get; set; }

    public virtual Challenge Challenge { get; set; }
}

public partial class Challenge
{
    public Challenge()
    {
        this.Ideations = new HashSet<Ideation>();
    }

    public long Id { get; set; }

    public virtual ICollection<Ideation> Ideations { get; set; }
}

public partial class BoxEntities : DbContext
{
    public TIBoxEntities()
        : base("name=BoxEntities")
    {

    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        throw new UnintentionalCodeFirstException();
    }

    public virtual DbSet<Ideation> Ideations { get; set; }
    public virtual DbSet<Challenge> Challenges { get; set; }
}

Also I tried to set ProxyCreationEnabled and LazyLoadingEnabled explicitly without no luck. The entity isn't loaded as a dynamic proxy as this debug session screenshot shows:

Debug

What else am I missing?

like image 413
Denys Denysenko Avatar asked Oct 02 '22 10:10

Denys Denysenko


1 Answers

A situation where this could happen is that the entity you are trying to load with Find is already attached to the context as a non-proxy object. For example:

using (var context = new MyContext())
{
    var ideation = new Ideation { Id = 1 }; // this is NOT a proxy
    context.Ideations.Attach(ideation);

    // other stuff maybe ...

    var anotherIdeation = context.Ideations.Find(1);
}

anotherIdeation will be the non-proxy that is already attached and it is not capable of lazy loading. It even wouldn't help to run a DB query with var anotherIdeation = context.Ideations.SingleOrDefault(i => i.Id == 1); because the default merge option for queries is AppendOnly, i.e. the new entity would only be added if there isn't already an attached entity with that key. So, anotherIdeation would still be a non-proxy.

You can check if the entity is already attached by using Local before you call Find in your GetById method:

bool isIdeationAttached = context.Ideations.Local.Any(i => i.Id == id);
like image 184
Slauma Avatar answered Oct 05 '22 12:10

Slauma