[英]What's the proper way to get data using Entity Framework so you can navigate through objects?
I have a .Net 4.5 MVC 5 database first project that I'm playing around with. 我有一个正在玩的.Net 4.5 MVC 5数据库第一个项目。 There's a data access layer (Entity Framework 6), a business logic layer and the MVC layer.
有数据访问层(实体框架6),业务逻辑层和MVC层。
If I have an object with relationships in the data layer: 如果我在数据层中有一个具有关系的对象:
namespace DataAccess
{
public class Course
{
public int CourseID { get; set; }
public string Title { get; set; }
public ICollection<Lecture> Lectures { get; set; }
public ICollection<Tutor> Tutors { get; set; }
}
public class Lecture
{
public int LectureID { get; set; }
public string Title { get; set; }
public DateTime Date { get; set; }
public ICollection<Student> Students { get; set; }
}
public class Tutor
{
public int TutorID { get; set; }
public string Name { get; set; }
}
public class Student
{
public int StudentID { get; set; }
public string Name { get; set; }
}
}
And in my business logic layer I have a method that gets courses: 在我的业务逻辑层中,我有一种获取课程的方法:
namespace BusinessLogic
{
public static IEnumerable<Course> GetCourses()
{
using (var db = new MyEntities())
{
return db.Courses.Include("Lectures").Include("Lectures.Students").Include("Tutors").ToList();
}
}
}
And I get the data using my controller like this: 然后使用我的控制器获取数据,如下所示:
public class HomeController : Controller
{
public ActionResult Index()
{
var courses = BusinessLogic.GetCourses();
return View(courses);
}
}
Why is it, when I query my data in the Razor view like this: 为什么这样,当我在Razor视图中查询数据时,如下所示:
var numLectures = courses.Lectures.Count;
var numStudents = courses.Lectures.Students.Count;
var tutorName = courses.Tutors.LastOrDefault().Name;
I get the application error System.ObjectDisposedException: The ObjectContext instance has been disposed and can no longer be used for operations that require a connection . 我收到应用程序错误System.ObjectDisposedException:ObjectContext实例已被处置,不能再用于需要连接的操作 。
I know the connection is disposed after the using statement has finished and that .ToList() will let me navigate the courses object, but how do I navigate the objects inside each course (ie lectures, students, tutors etc.)? 我知道在using语句完成后会断开连接,并且.ToList()将使我可以浏览课程对象,但是如何浏览每门课程中的对象(即讲座,学生,导师等)?
Your navigation properties need to be declared as virtual
: 您的导航属性需要声明为
virtual
:
namespace DataAccess
{
public class Course
{
public int CourseID { get; set; }
public string Title { get; set; }
public virtual ICollection<Lecture> Lectures { get; set; }
public virtual ICollection<Tutor> Tutors { get; set; }
}
public class Lecture
{
public int LectureID { get; set; }
public string Title { get; set; }
public DateTime Date { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
...
}
When these lazy loadable properties are not marked as virtual
, the EF dynamic proxies cannot override them and you will never be able to navigate from one entity to a (set of) another. 当这些可延迟加载的属性未标记为
virtual
,EF动态代理将无法覆盖它们,并且您将永远无法从一个实体导航到另一个实体。
Another bit of advice: use the strongly-typed .Include
when eager loading: 另一点建议:急于加载时,请使用强类型的
.Include
:
namespace BusinessLogic
{
public static IEnumerable<Course> GetCourses()
{
using (var db = new MyEntities())
{
return db.Courses
.Include(x => x.Lectures.Select(y => y.Students))
.Include(x => x.Tutors)
.ToList();
}
}
}
I think the problem is because one (or more than one) property that you are calling in your View is (are) not included in your query. 我认为问题是因为查询中不包含您在View中调用的一个(或多个)属性。 Make sure you are including all the navigation properties you need in the view.
确保在视图中包含所需的所有导航属性。 Try with this query:
尝试使用以下查询:
using (var db = new MyEntities())
{
return db.Courses.db.Courses.Include(c=>c.Lectures.Select(l=>l.Students)).Include(c=>c.Tutors).ToList()
}
If you need to add another relative property that you use in your View, then add another Include
call for that property. 如果您需要添加在View中使用的另一个相对属性,请为该属性添加另一个
Include
调用。
Another thing, when you need to eager load two levels (like Lectures.Students
), you don't need to add a Include
call for each level, with the call that you do for the second level is enough to include both. 另一件事,当您需要加载两个级别(例如
Lectures.Students
)时,不需要为每个级别添加一个Include
调用,而您对第二个级别所做的调用就足以包含这两个级别。 Could be this way: 可能是这样的:
.Include("Lectures.Students") // as you did it
Or: 要么:
.Include(c=>c.Lectures.Select(l=>l.Students))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.