0

I previously had the following line of code from within my AdminController that was successfully returning a list of relevant subsections from within a course:

[AcceptVerbs(HttpVerbs.Get)]
public JsonResult GetCourseSections(int courseID)
{ 
  var Sections = dbcontext.CourseSection.Where(cs => cs.CourseID.Equals(courseID)).Select(x => new
  {            
    sectionID = x.CourseSectionID,
    sectionTitle = x.Title
  );
  return Json(Sections, JsonRequestBehavior.AllowGet);
}

I was informed to take this out of the controller as it was bad practice to call dbcontext and so i moved this to the AdminViewModel. Within my AdminViewModel I have a variable public List CourseSectionList { get; set; } and I am trying to populate this variable with the JSON request details. My code is as follows:

AdminViewModel

public void GetCourseSectionDetails(int courseID)
{
  var Sections = dbcontext.CourseSection.Where(cs => cs.CourseID.Equals(courseID)).Select(x => new CourseSection
  {
    CourseSectionID = x.CourseSectionID,
    Title = x.Title
  });
  this.CourseSectionList = Sections.ToList();
}

AdminController

[AcceptVerbs(HttpVerbs.Get)]
public JsonResult GetCourseSections(int courseID)
{ 
  avm.GetCourseSectionDetails(courseID);
  var Sections = avm.CourseSectionList.Where(cs => cs.CourseID.Equals(courseID)).Select(x => new
  {            
    sectionID = x.CourseSectionID,
    sectionTitle = x.Title
  });
  System.Diagnostics.EventLog.WriteEntry("Application", "JSON=" + Sections.ToList(), System.Diagnostics.EventLogEntryType.Error);
  return Json(Sections, JsonRequestBehavior.AllowGet);
}

I am getting the error The entity or complex type 'MetaLearning.Data.CourseSection' cannot be constructed in a LINQ to Entities query. How can I populate this.CourseSectionList variable using the Sections?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Jay
  • 3,012
  • 14
  • 48
  • 99

3 Answers3

2

As pointed by your error message, you can't, in linq to entities, use a

.Select(m => new <Entity>{bla bla})

where <Entity>... is one of your model's entity.

So either you use a "non model" class (DTO), which has the properties you need, or you have to enumerate before selecting (because linq to objects has not that limitation)

.ToList()
.Select(m => new <Entity>{bla bla});

You can find some nice explanations of why it's not possible here

EDIT :

you may also do something like that, if you wanna retrive only some properties of your entity, and don't wanna use a DTO :

return ctx
        .CourseSection
         .Where(cs => cs.CourseID.Equals(courseID))
         //use an anonymous object to retrieve only the wanted properties
         .Select(x => new 
                {
                    c= x.CourseSectionID,
                    t= x.Title,
                })
         //enumerate, good bye linq2entities
         .ToList()
         //welcome to linq2objects
         .Select(m => new CourseSection {
                     CourseSectionID = m.c,
                     Title = m.t,
          })
          .ToList();
Community
  • 1
  • 1
Raphaël Althaus
  • 59,727
  • 6
  • 96
  • 122
0

You don't need to repeat the same code in the controller, but directly pass the list to the view.

This being said I am informing you that placing data access code in your view model is even worse practice than keeping it in the controller. I would recommend you having a specific DAL layer:

public interface IRepository
{
    public IList<CourseSection> GetSections(int courseID);
}

which would be implemented:

public class RepositoryEF : IRepository
{
    public IList<CourseSection> GetSections(int courseID)
    {
        using (ctx = new YourDbContextHere())
        {
            return ctx
                .CourseSection
                .Where(cs => cs.CourseID.Equals(courseID))
                .Select(x => new CourseSection
                {
                    CourseSectionID = x.CourseSectionID,
                    Title = x.Title,
                })
                .ToList();
        }
    }
}

and finally have your controller take the repository as dependency:

public class SomeController : Controller
{
    private readonly IRepository repo;
    public SomeController(IRepository repo)
    {
        this.repo = repo;
    }

    [AcceptVerbs(HttpVerbs.Get)]
    public ActionResult GetCourseSections(int courseID)
    { 
        var sections = this.repo.GetSections(courseID);
        return Json(sections, JsonRequestBehavior.AllowGet);
    }
}
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
0

I did this as follows using Darin's answer as a guide:

ViewModel

public void GetCourseSectionDetails(int courseID)
    {
        this.CourseSectionList = dbcontext.CourseSection.AsEnumerable().Where(cs => cs.CourseID.Equals(courseID)).Select(x => new CourseSection
        {
            CourseSectionID = x.CourseSectionID,
            Title = x.Title
        }).ToList();
    }

Controller

[AcceptVerbs(HttpVerbs.Get)]
    public JsonResult GetCourseSections(int courseID)
    {             
        var sections = avm.CourseSectionList;
        return Json(sections, JsonRequestBehavior.AllowGet);
    }
Michael Eakins
  • 4,149
  • 3
  • 35
  • 54
Jay
  • 3,012
  • 14
  • 48
  • 99