如何禁用泛型类型的复杂类型字段的延迟加载?

时间:2015-02-18 13:41:42

标签: c# entity-framework generics lazy-loading

我正在使用EF与我的数据库进行交互。 我已经实现了一个通用存储库:

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

它有这样的方法:

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

还有两种型号:

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; }
}

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; }
}

在MyDataContext OnModelCreating方法中我链接模型:

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

在创建GenericDbRepository&lt; Task&gt;的实例时,一切正常。并执行GenericDbRepository(someId)。

但是如果TEntity有复杂的类型字段(在我的情况下它是ICollection&lt; Task&gt; Tasks),则有一个异常&#34; ObjectContext实例已被处理,不能再用于需要连接的操作&# 34。

据我所知,MyDataContext在GetById方法中的返回值之后被释放,之后的任务不可用。

我尝试这样做:

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

它对所描述的问题有很大的帮助,但又创建了另一个:没有链接到Project的任务,我总是得到空的Tasks字段。所以,这不是一个选择。

所以,问题是如何在上下文处理之前获得这种复杂的类型字段值。

2 个答案:

答案 0 :(得分:2)

导航属性导致错误的原因是因为您在导航属性加载之前处置了上下文。

要避免此类错误,您可以在通用存储库中使用Tasks方法急切加载Project Include,例如,您可以执行此操作:

 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;
 }

使用此方法,您可以找到应用倍数的元素,在您的情况下,可以是这样的:

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

答案 1 :(得分:0)

您可以尝试使用.Include方法并在查询父实体之前包含所需的子属性。 关于加载相关实体的Here is a good article