Dmitry Maksakov
Dmitry Maksakov

Reputation: 1701

How to disable lazy loading for complex type fields of generic type?

I`m using EF to interact with my database. I have implemented a generic repository:

public class GenericDbRepository<TEntity> 
        : IGenericRepository<TEntity> where TEntity : class

it has such method:

public virtual TEntity GetById(int id)
{
    using (MyDataContext context = new MyDataContext())
    {
       return context.Set<TEntity>().Find(id);
    }
}

Also there are two models:

public class Project
{
    public Project()
    {
        Tasks = new HashSet<Task>();
    }

    public int Id { get; set; }

    public string Name { get; set; }

    public bool Enabled { get; set; }

    public State State { get; set; }

    public DateTime? ChangeDate { get; set; }

    public virtual ICollection<Task> Tasks { get; set; }
}

and

public class Task
{
    public int Id { get; set; }

    public int ProjectId { get; set; }

    public string Name { get; set; }

    public int Interval { get; set; }

    public DateTime NextStart { get; set; }
}

In MyDataContext OnModelCreating method I`m linking models:

 modelBuilder.Entity<Project>()
            .HasMany(e => e.Tasks);

Everything works fine, when creating an instance of GenericDbRepository<Task> and execute GenericDbRepository(someId).

But if TEntity has complex type field (in my case it is ICollection<Task> Tasks), a have an exception "The ObjectContext instance has been disposed and can no longer be used for operations that require a connection".

I understand that MyDataContext was disposed after return value in GetById method and Tasks are not available after that.

I try to do this:

public MyDataContext()
    : base("name=MyDataContext") 
{
    this.Configuration.LazyLoadingEnabled = false;
}

It helps a lot with described problem, but creates another one: Tasks not linking to Project and I`m always getting empty Tasks field. So, this not an option.

So, the question is how to get such complex type fields values before context dispose.

Upvotes: 3

Views: 406

Answers (2)

ocuenca
ocuenca

Reputation: 39326

The reason your navigation property is causing errors is because you're disposing the context, prior to the navigation property being loaded.

To avoid this kind of error you can eagerly load the Tasks for your Project using Include method in your generic repository,for example, you could do this:

 public virtual T FindElement(Func<T, bool> where, params Expression<Func<T, object>>[] navigationProperties)
 {
        T item = null;
        using (var context = new Entities())
        {
            IQueryable<T> dbQuery = context.Set<T>();

            //Apply eager loading
            foreach (Expression<Func<T, object>> navigationProperty in navigationProperties)
                dbQuery = dbQuery.Include<T, object>(navigationProperty);

            item = dbQuery
                  .FirstOrDefault(where); //Apply where clause
        }
        return item;
 }

Using this method you can find a element applying multiples includes, in your case, could be this way:

var repository=new GenericDbRepository<Project>();
var project=repository.FindElement(p=>p.Id==23, p=>p.Tasks, p=>p.State);

Upvotes: 2

Alex Kopachov
Alex Kopachov

Reputation: 733

You can try to use .Include method and include child properties you need before querying the parent entities. Here is a good article about loading of related entities

Upvotes: 0

Related Questions