繁体   English   中英

如何在Entity Framework 6中延迟加载关系?

[英]How can I lazy load relation in Entity Framework 6?

我有一个项目,我正在使用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类。 (为简单起见,我删除了大部分代码。)

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."}

我不确定它是如何处理的? 我在using(){}块中返回View() 所以它应该在我访问后处理。

我可以切换到急切加载“下面的代码”来解决问题,但我想知道如何使用延迟加载做同样的事情。

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关系?

你不应该访问MyUser.TimeZoneSomeWrapper

你在那里做的是浅拷贝用户到MyUser,混合域模型 (一些调用实体模型)视图模型 这不是一个好习惯,因为领域模型永远不应该暴露给公众。

您不应该从Domain ModelView Model进行浅层复制。 相反,您需要使用对象对象映射器(如AutoMapper)进行深层复制。

延迟加载

实体框架已经提供延迟加载,但您无法在检索数据后立即处理DbContext

相反,您需要使用IoC容器(如Autofac,Ninject)注入MyAppContent。

例如,

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 ,它的范围远小于该范围,特别是在渲染视图期间不可用。 请注意,返回内部的事实是无关紧要的; 视图呈现可以在动作范围之外发生。

无论长短,您只需要确保您拥有一个能够在请求期限内存活的上下文。 最简单的方法是使用依赖注入容器将其注入控制器,并将其设置为请求范围。 如果你不想走那么远,只需在你的控制器上做一个ivar(它本质上是请求范围的)。 您还应该记得在控制器上覆盖Dispose ,在这种情况下,要正确处理上下文:

private readonly MyAppContent conn = new MyAppContent();

// other controller code

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        conn.Dispose();
    }
    base.Dispose(disposing);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM