C# 在释放上下文后,如何从实体框架(首先是数据库)返回包含导航属性的模型?

C# 在释放上下文后,如何从实体框架(首先是数据库)返回包含导航属性的模型?,c#,.net,asp.net-mvc,entity-framework,C#,.net,Asp.net Mvc,Entity Framework,我所问的实际上比问题的标题要宽泛一点……但这是一个具体的问题 我试图精简我的控制器,并将所有业务逻辑/与实体框架的交互移动到服务层,这样我的控制器就根本不需要上下文,我认为这是“正确”的方法 问题是,当我创建一个返回域模型的服务层方法时,它不包含导航属性,一旦我在控制器中调用此方法并需要访问这些导航属性,上下文就已经被释放。然后,这迫使我对其他服务层方法进行多次调用,以获得所需的其余属性,以便创建视图模型 我确信问题在于我没有以正确的方式创建我的方法,或者缺少适合这种情况的正确体系结构的某些组件

我所问的实际上比问题的标题要宽泛一点……但这是一个具体的问题

我试图精简我的控制器,并将所有业务逻辑/与实体框架的交互移动到服务层,这样我的控制器就根本不需要上下文,我认为这是“正确”的方法

问题是,当我创建一个返回域模型的服务层方法时,它不包含导航属性,一旦我在控制器中调用此方法并需要访问这些导航属性,上下文就已经被释放。然后,这迫使我对其他服务层方法进行多次调用,以获得所需的其余属性,以便创建视图模型

我确信问题在于我没有以正确的方式创建我的方法,或者缺少适合这种情况的正确体系结构的某些组件,所以这里有一些代码来演示我正在做什么

服务层方法:

        public IEnumerable<Paper> GetPapersForReview(int userID, string courseID, string role)
        {
            using (USGEntities context = new USGEntities())
            {
                IEnumerable<Paper> models = (from a in context.Papers
                                             join b in context.Users_Roles on a.Paper_Types.Course_ID equals b.Course_ID
                                             where a.Status == "REV" && a.Deleted == false && b.User_ID == userID && b.Role.Name == role && b.Course_ID == courseID
                                             select a).ToList();

                return models;
            }
        }
        public JsonResult GetPapersForReview(string courseID)
        {
            int user_id = new User().GetUserIDByDomainAccount(User.Identity.Name);

            var vm = (from a in new PaperService().GetPapersForReview(user_id, courseID, "Reviewer")
                      select new PaperViewModel()
                      { 
                          Paper_ID = a.ID,
                          Proposal_ID = a.Proposal_ID,
                          Expected_Start_Date = a.Expected_Start_Date
                      }).Distinct().ToList();

            foreach (var paper in vm)
            {
                Proposal proposal = new ProposalService().GetProposal(paper.Proposal_ID);
                Paper_Types paper_type = new PaperTypeService().GetPaperTypeByPaper(paper.Paper_ID);
                paper.Paper_Type = paper_type.Description;
                paper.Resources = new PaperService().GetResourceList(paper.Paper_ID);
                paper.Proposal_Title = proposal.Title;
                paper.Author = new UserService().GetNameByUserID(proposal.Author_User_ID);
            }

            return Json(vm, JsonRequestBehavior.AllowGet);
        }
因此,您可以看到,在我调用服务层方法并获得我可以直接访问的属性之后,我必须通过该方法进行循环,并进行其他调用以获得我需要的其余属性。我知道这不是正确的做事方式。那么,我如何更好地构建东西,以从服务层返回我所需要的一切呢


其他一些相关问题是:我是否应该从服务层返回IEnumerables或其他内容,是否需要在这两个位置调用ToList()?

您有
。包括
扩展名:

public IEnumerable<Paper> GetPapersForReview(int userID, string courseID, string role)
{
    using (USGEntities context = new USGEntities())
    {
        var result = context.Papers
            .Include(paper => paper.User)
            .Where(paper => paper.Status == "REV" && paper.Deleted == false && paper.User_ID == userID && paper.User.Role.Name == role && paper.Course_ID == courseID)
            .ToList();
        return result;
    }
}

您有
。包括
扩展名:

public IEnumerable<Paper> GetPapersForReview(int userID, string courseID, string role)
{
    using (USGEntities context = new USGEntities())
    {
        var result = context.Papers
            .Include(paper => paper.User)
            .Where(paper => paper.Status == "REV" && paper.Deleted == false && paper.User_ID == userID && paper.User.Role.Name == role && paper.Course_ID == courseID)
            .ToList();
        return result;
    }
}

您必须在服务方法中使用
Include
。使用即时加载。如果我使用即时加载,然后将该模型传递回我的控制器,如果我不在我的上下文中,如何访问控制器中包含的模型?您是否仍然使用像paper.Proposal.Title这样的“.”方法?如果是这样,这不是实体框架的一个特性吗?目标是从我的控制器中删除对实体框架和数据上下文的引用,并且只在我的服务层中引用它。您必须在服务方法中使用
Include
。使用即时加载。如果我使用即时加载,然后将该模型传递回我的控制器,如果不在上下文中,如何访问控制器中包含的模型?您是否仍然使用像paper.Proposal.Title这样的“.”方法?如果是这样,这不是实体框架的一个特性吗?目标是从我的控制器中删除对实体框架和数据上下文的引用,并且只在我的服务层中引用它。因此,如果我使用include,并且仍然返回模型类型纸张,那么在我的控制器中,我如何访问包含的导航属性而不使用对上下文的引用?是否会“预先填充”该导航属性的所有字段?因此,像上面提到的那样,是渴望加载,而不是懒惰加载?除了潜在的冗长数据库调用的明显缺点之外,此方法还有其他缺点吗?您可以为返回的数据创建
ViewModel
,并将其传递给视图。至于起起伏伏,请阅读完整的文档。在我上面展示的控制器方法中,我正在从服务层调用构建视图模型……我的问题是,我是否可以访问控制器中包含的导航属性,而不必位于数据上下文中?因为如果我需要那里的数据上下文,那么这就有点违背了从控制器中提取实体框架并只在服务层中使用它的目的。
.Include
方法最适合数据层,因为在那里可以从数据库中提取数据。viewmodel应该是映射到实际模型(已包含所有子元素)的一组属性。检索数据后,可以使用
.Select(p=>newmyviewmodel{//code here}).ToList()创建viewmodel。因此,要回答您的问题,您不需要在控制器中使用
。包括
。好的,但是您是说我应该在服务层中构建viewmodel吗?这似乎违背了分离关注点的原则,因为viewmodels与视图紧密耦合,服务层方法不应该知道关于视图的任何信息。这样做还可能限制服务层方法仅在一个视图中使用。除非我不理解你的意思……那么,如果我使用include,并且我仍然返回模型类型纸张,那么在我的控制器中,我将如何访问包含的导航属性而不使用对上下文的引用?是否会“预先填充”该导航属性的所有字段?因此,像上面提到的那样,是渴望加载,而不是懒惰加载?除了潜在的冗长数据库调用的明显缺点之外,此方法还有其他缺点吗?您可以为返回的数据创建
ViewModel
,并将其传递给视图。至于起起伏伏,请阅读完整的文档。在我上面展示的控制器方法中,我正在从服务层调用构建视图模型……我的问题是,我是否可以访问控制器中包含的导航属性,而不必位于数据上下文中?因为如果我需要那里的数据上下文,那么这就有点违背了从控制器中提取实体框架并只在服务层中使用它的目的。
.Include
方法最适合数据层,因为在那里可以从数据库中提取数据。viewmodel应该是映射到实际模型(已包含所有子元素)的一组属性。检索数据后,可以使用
.Select(p=>newmyviewmodel{//code here}).ToList()创建viewmodel。所以要回答你的问题,你不需要