简体   繁体   中英

How do I return a Model from Entity Framework (Database First) that includes the Navigation Properties after the context is disposed?

What I am asking is actually a little more broad than the question title...but that is kind of the specific question.

I am trying to thin out my controllers and move all business logic / interaction with Entity Framework into a Service Layer so that my controllers don't need the context at all, which I believe is the "right" way to do things.

The problem is that when I create a Service Layer method that returns a domain model, it does not contain the Navigation Properties and once I am calling this method in my controller and need to access these navigation properties, the context has already been disposed. This then forces me to make multiple calls out to other Service Layer methods to get the rest of the properties I need so that I can create my View Model.

I'm sure the issue is that I am not creating my methods in the proper way or missing some component of the correct architecture for this situation so here is some code to demonstrate what I am doing.

Service Layer method:

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

Controller method:

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

So you can see after I make the call to the Service Layer method and get the properties that I have direct access to, I then have to loop back through that and make additional calls to get the rest of the properties that I need. I know this is not the right way to do things. So how do I structure things better to return everything I need from the Service Layer?

Some other related questions are: should I be returning IEnumerables or something else from the Service Layer and do I need to be calling ToList() in both places?

You have the .Include extension:

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

You can even use .ThenInclude if you have multiple levels:

.Include(p => p.Item)
    .ThenInclude(p => p.SubItem)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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