Reputation: 1701
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
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
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