如何在 Entity Framework 6 中延迟加载关系?
How can I lazy load relation in Entity Framework 6?
我有一个项目,我正在使用 Entity Framework 6 和 ASP.NET MVC 5。
我需要使用延迟加载而不是急切。换句话说,我希望能够在不使用 .Include()
的情况下检索父模型后访问 relation/child
这是我的简单用例
public ActionResult Test(int id)
{
using(var conn = new MyAppContent())
{
var user = conn.User.Where(u => u.Id == id).First();
var capsule = new SomeWrapper(user)
return View(capsule);
}
}
这是我的 SomeWrapper
class 简而言之。 (为了简单起见,我删除了大部分代码。)
public SomeWrapper
{
public User MyUser { get; set; }
public SomeWrapper(User user)
{
MyUser = user;
}
// Of course this class does more than this.
}
这是我的User
模型
public User
{
public int Id { get; set; }
public string Username { get; set; }
[ForeignKey("TimeZone")]
public int? TimeZoneId { get; set; }
}
现在我想从视图中知道用户所在的时区。所以我做了这样的事情
@model App.SomeWrapper
<p>Model.MyUser.Username<p>
<p>Model.MyUser.TimeZone.Name<p>
但是,当我尝试访问 TimeZone.Name 时,出现以下错误
{"The ObjectContext instance has been disposed and can no longer be used for operations that require a connection."}
不知道是怎么处理的?我 return View()
在我的 using(){}
块中。所以它应该在我访问它之后被处理掉。
我可以切换到预加载 "code below" 来解决问题,但我想知道如何使用延迟加载来做同样的事情。
public ActionResult Test(int id)
{
using(var conn = new MyAppContent())
{
var user = conn.User.Where(u => u.Id == id).Include(x => x.TimeZone).First();
var capsule = new SomeWrapper(user)
return View(capsule);
}
}
如何正确延迟加载 TimeZone
关系?
您不应在 SomeWrapper
内访问 MyUser.TimeZone
。
你刚才做的是浅拷贝用户到MyUser,然后混合域模型(有些叫实体模型)和查看模型 .这不是一个好的做法,因为域模型永远不应该暴露给 public。
你不应该从域模型浅拷贝到视图模型。相反,您需要使用对象-对象映射器进行深度复制,例如 AutoMapper.
延迟加载
Entity Framework 已经提供延迟加载,但是您 不能在检索数据后立即处理 DbContext。
相反,您需要使用 IoC 容器(例如 Autofac)注入 MyAppContent,Ninject。
例如,
public class MyController : Controller
{
private readonly MyAppContent _myAppContent;
public MyController(MyAppContent myAppContent)
{
_myAppContent = myAppContent;
}
public ActionResult Test(int id)
{
var user = _myAppContent.User.Where(u => u.Id == id).First();
...
}
}
问题是您的上下文应该是请求范围的。通过在您的操作中使用 using
,它的范围远小于该范围,尤其是在视图呈现期间不可用。请注意,return 在里面这一事实是无关紧要的;视图渲染可以发生在动作范围之外。
总而言之,您只需要确保您的上下文能够在请求的长度内继续存在。最简单的方法是使用依赖注入容器将其注入到控制器中,并将其设置为请求范围。如果您不想走那么远,只需将它设为控制器上的一个 ivar(本质上是请求范围的)。你还应该记住在你的控制器上覆盖 Dispose
,在这种情况下,正确处理上下文:
private readonly MyAppContent conn = new MyAppContent();
// other controller code
protected override void Dispose(bool disposing)
{
if (disposing)
{
conn.Dispose();
}
base.Dispose(disposing);
}
我有一个项目,我正在使用 Entity Framework 6 和 ASP.NET MVC 5。
我需要使用延迟加载而不是急切。换句话说,我希望能够在不使用 .Include()
这是我的简单用例
public ActionResult Test(int id)
{
using(var conn = new MyAppContent())
{
var user = conn.User.Where(u => u.Id == id).First();
var capsule = new SomeWrapper(user)
return View(capsule);
}
}
这是我的 SomeWrapper
class 简而言之。 (为了简单起见,我删除了大部分代码。)
public SomeWrapper
{
public User MyUser { get; set; }
public SomeWrapper(User user)
{
MyUser = user;
}
// Of course this class does more than this.
}
这是我的User
模型
public User
{
public int Id { get; set; }
public string Username { get; set; }
[ForeignKey("TimeZone")]
public int? TimeZoneId { get; set; }
}
现在我想从视图中知道用户所在的时区。所以我做了这样的事情
@model App.SomeWrapper
<p>Model.MyUser.Username<p>
<p>Model.MyUser.TimeZone.Name<p>
但是,当我尝试访问 TimeZone.Name 时,出现以下错误
{"The ObjectContext instance has been disposed and can no longer be used for operations that require a connection."}
不知道是怎么处理的?我 return View()
在我的 using(){}
块中。所以它应该在我访问它之后被处理掉。
我可以切换到预加载 "code below" 来解决问题,但我想知道如何使用延迟加载来做同样的事情。
public ActionResult Test(int id)
{
using(var conn = new MyAppContent())
{
var user = conn.User.Where(u => u.Id == id).Include(x => x.TimeZone).First();
var capsule = new SomeWrapper(user)
return View(capsule);
}
}
如何正确延迟加载 TimeZone
关系?
您不应在 SomeWrapper
内访问 MyUser.TimeZone
。
你刚才做的是浅拷贝用户到MyUser,然后混合域模型(有些叫实体模型)和查看模型 .这不是一个好的做法,因为域模型永远不应该暴露给 public。
你不应该从域模型浅拷贝到视图模型。相反,您需要使用对象-对象映射器进行深度复制,例如 AutoMapper.
延迟加载
Entity Framework 已经提供延迟加载,但是您 不能在检索数据后立即处理 DbContext。
相反,您需要使用 IoC 容器(例如 Autofac)注入 MyAppContent,Ninject。
例如,
public class MyController : Controller
{
private readonly MyAppContent _myAppContent;
public MyController(MyAppContent myAppContent)
{
_myAppContent = myAppContent;
}
public ActionResult Test(int id)
{
var user = _myAppContent.User.Where(u => u.Id == id).First();
...
}
}
问题是您的上下文应该是请求范围的。通过在您的操作中使用 using
,它的范围远小于该范围,尤其是在视图呈现期间不可用。请注意,return 在里面这一事实是无关紧要的;视图渲染可以发生在动作范围之外。
总而言之,您只需要确保您的上下文能够在请求的长度内继续存在。最简单的方法是使用依赖注入容器将其注入到控制器中,并将其设置为请求范围。如果您不想走那么远,只需将它设为控制器上的一个 ivar(本质上是请求范围的)。你还应该记住在你的控制器上覆盖 Dispose
,在这种情况下,正确处理上下文:
private readonly MyAppContent conn = new MyAppContent();
// other controller code
protected override void Dispose(bool disposing)
{
if (disposing)
{
conn.Dispose();
}
base.Dispose(disposing);
}