如何禁用泛型复杂类型字段的延迟加载?
How to disable lazy loading for complex type fields of generic type?
我正在使用 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 实例并执行 GenericDbRepository(someId) 时一切正常。
但是如果 TEntity 具有复杂类型字段(在我的例子中是 ICollection Tasks),则会出现异常 "The ObjectContext instance has been disposed and can no longer be used for operations that require a connection"。
我了解到 MyDataContext 在 GetById 方法中的 return 值之后被处理,之后任务不可用。
我尝试这样做:
public MyDataContext()
: base("name=MyDataContext")
{
this.Configuration.LazyLoadingEnabled = false;
}
它对描述的问题有很大帮助,但会产生另一个问题:任务未链接到项目,我总是得到空的任务字段。所以,这不是一个选择。
所以,问题是如何在上下文处理之前获取如此复杂的类型字段值。
您可以尝试使用 .Include 方法并在查询父实体之前包含您需要的子属性。
Here is a good article关于加载相关实体
您的导航 属性 导致错误的原因是您在加载导航 属性 之前处理上下文。
为避免此类错误,您可以使用通用存储库中的 Include
方法为您的 Project
加载 Tasks
,例如,您可以这样做:
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);
我正在使用 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
但是如果 TEntity 具有复杂类型字段(在我的例子中是 ICollection
我了解到 MyDataContext 在 GetById 方法中的 return 值之后被处理,之后任务不可用。
我尝试这样做:
public MyDataContext()
: base("name=MyDataContext")
{
this.Configuration.LazyLoadingEnabled = false;
}
它对描述的问题有很大帮助,但会产生另一个问题:任务未链接到项目,我总是得到空的任务字段。所以,这不是一个选择。
所以,问题是如何在上下文处理之前获取如此复杂的类型字段值。
您可以尝试使用 .Include 方法并在查询父实体之前包含您需要的子属性。 Here is a good article关于加载相关实体
您的导航 属性 导致错误的原因是您在加载导航 属性 之前处理上下文。
为避免此类错误,您可以使用通用存储库中的 Include
方法为您的 Project
加载 Tasks
,例如,您可以这样做:
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);