我正在使用EF codefirst。我对实体中的关系感到困惑。我有两个实体Student
和Standard
。如下所示
public class Student
{
public int StudentId { get; set; }
public string StudentName { get; set; }
public int StdandardId { get; set; }
}
public class Standard
{
public int StandardId { get; set; }
public string StandardName { get; set; }
public string Description { get; set; }
}
他们有一对多的关系。 我可以通过像这样的简单连接表达式来完成这个
var list = StudentList.Join
(StandardList,c => c.StdandardId,o => o.StandardId,(c, o) => new
{
StudentId = c.StudentId,
StudentName = c.StudentName,
StandardName = o.StandardName
});
那我为什么要配置像一对多的关系,比如
public class Student
{
public Student() { }
public int StudentId { get; set; }
public string StudentName { get; set; }
public int StdandardId { get; set; }
public virtual Standard Standard { get; set; }
}
public class Standard
{
public Standard()
{
Students = new List<Student>();
}
public int StandardId { get; set; }
public string StandardName { get; set; }
public string Description { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
是否有任何关键的好处。?哪一个表现不错?
答案 0 :(得分:3)
导航属性(Students
)是隐式连接。但它是外连接。如果您明确加入,则可以强制实施内部联接,这通常会表现得更好。如果性能至关重要,请这样做。
所以给自己两个机会。创建导航属性并在必要时显式连接。
导航属性的好处是更简洁的语法。 e.g。
from standard in Standards
select new { standard.StandardName , NrOfStudents = standard.Students.Count() })
对于此查询,您始终需要外部联接,因为您还希望报告零学生的标准。
或隐含的SelectMany
:
from standard in Standards
where standard.StandardId == id
from student in standard.Students
select new { student. ... }
导航属性可帮助您在没有这种详细的连接语法的情况下执行连接。
答案 1 :(得分:2)
这个问题的答案可以达到论文的大小。
我会尽力保持它必不可少。简而言之,外键用于确保参照完整性。
在你的select语句中,它可能没有什么区别,但考虑更新,插入和删除语句,以及你必须采取的障碍,以便将所有内容级联到最后一个表。
让我们假设您的外键约束设置为Cascade
。无论何时对您的mastertable进行更改,都会将更改级联到每个子表。您必须手动加入语句中的每个表来实现相同的目标。
如果约束设置为Restrict
,只要仍有Student
引用该约束,您就无法删除Standards
。同样,你必须每次在你的陈述中手工检查这一点。
你很可能会在脑海中做到这一点,但是你会犯错误,然后当资金到位时,你可能会遇到不一致的数据。
然后EF很舒服。
我可以加入我的数据,但如果有外键和tehrefore关系,我可以写
var students = context.Students.Include(o => o.Enrollments);
并在我的视图中使用
@foreach(var enrollment in Model.Enrollments)
{
//...
}
从本质上讲,这不是纯粹与实体框架相关的问题,而是与关系数据库相关的问题。