Entity Framework 6 - 使用导航属性从 0:M 关系加载数据
Entity Framework 6 - loading data from a 0:M relationship using navigational properties
这些天我越来越少使用连接,并尽可能依赖导航属性。
这是一个非常基本的架构:
用户:
Id int
Surname string
FirstName string
注册人数:
Id int
UserId int (foreign key for Users.Id)
EnrolmentName string
StartDate datetime
EndDate datetime
一个用户在 Enrolments
table 中可能有 0 个、1 个或多个与其相关的注册。
现在在查询中,我想 select 所有用户行,以及他们第一次注册的 EnrolmentName 列。我喜欢尽可能精简我的查询,并且只 select 我需要从数据库中获取的内容。如果没有必要,我不喜欢返回整个实体。
这是我的查询(我 select 将相关数据直接放入视图模型)。
IList<UserVm> rows = db.Users
.Select(
x => new UserVm
{
Id = x.Id,
Surname = x.Surname,
FirstName = x.FirstName,
FirstEnrolmentName = x.Enrolments.OrderBy(o => o.StartDate).FirstOrDefault().EnrolmentName
}
)
.ToList();
我遇到的问题是它可以工作,但我认为当我遇到没有注册的用户时它应该会失败。我希望以下行会抱怨无法在空对象上找到 EnrolmentName
列。
FirstEnrolmentName = x.Enrolments.OrderBy(o => o.StartDate).FirstOrDefault().EnrolmentName
实际发生的是,它会将 EnrolmentName
列保留为 NULL,因为该用户没有 Enrolment
记录。
我想知道:
为什么这个查询有效,并且不会对 0 Enrolments
.
的学生造成错误
是否有更简洁的查询编写方式,以便它仍然只有 1 次访问数据库,并且仍然只有 selects 所需的列子集,而不是所有列.
你说得对,你应该 select 只使用你实际计划使用的属性,从而将尽可能少的数据传输到你的本地进程。
LINQ 知道两种语句:构成查询的语句和将执行查询的语句。作曲家是 return IQueryable<...>
(或 IEnumerable<...>
)的 LINQ 方法,执行者是 return 和 IQueryable
,但 TResult
。例如 ToList
、FirstOrDefault
、Any
、Max
、...
你应该始终确保执行器是你语句的最后一个,除非你绝对确定执行器后面的语句不会限制数据量。
db.Users.Select(user => new UserVm
{
...
FirstEnrolMentName = user.Enrolments
.OrderBy(enrolment => enrolment.StartDate)
.FirstOrDefault()
.EnrolmentName,
});
我想知道如果您有一个没有任何 Enrolments
的用户,这是否也有效。我的第一个猜测是 FirstOrDefault
会 return 为空,因此当你想获得 EnrolmentName
时你会有一个 ArgumentNullException
另一个问题是您首先 select 一个完整的 Enrolment
,然后您丢弃了除名称之外的所有注册属性。最好只 select 您计划使用的属性,然后使用 FirstOrDefault
:
var result = db.Users.Select(user => new UserVm
{
...
FirstEnrolMentName = user.Enrolments
.OrderBy(enrolment => enrolment.StartDate)
.Select(enrolment => enrolment.EnrolmentName)
.FirstOrDefault(),
});
这些天我越来越少使用连接,并尽可能依赖导航属性。
这是一个非常基本的架构:
用户:
Id int
Surname string
FirstName string
注册人数:
Id int
UserId int (foreign key for Users.Id)
EnrolmentName string
StartDate datetime
EndDate datetime
一个用户在 Enrolments
table 中可能有 0 个、1 个或多个与其相关的注册。
现在在查询中,我想 select 所有用户行,以及他们第一次注册的 EnrolmentName 列。我喜欢尽可能精简我的查询,并且只 select 我需要从数据库中获取的内容。如果没有必要,我不喜欢返回整个实体。
这是我的查询(我 select 将相关数据直接放入视图模型)。
IList<UserVm> rows = db.Users
.Select(
x => new UserVm
{
Id = x.Id,
Surname = x.Surname,
FirstName = x.FirstName,
FirstEnrolmentName = x.Enrolments.OrderBy(o => o.StartDate).FirstOrDefault().EnrolmentName
}
)
.ToList();
我遇到的问题是它可以工作,但我认为当我遇到没有注册的用户时它应该会失败。我希望以下行会抱怨无法在空对象上找到 EnrolmentName
列。
FirstEnrolmentName = x.Enrolments.OrderBy(o => o.StartDate).FirstOrDefault().EnrolmentName
实际发生的是,它会将 EnrolmentName
列保留为 NULL,因为该用户没有 Enrolment
记录。
我想知道:
为什么这个查询有效,并且不会对 0
Enrolments
. 的学生造成错误
是否有更简洁的查询编写方式,以便它仍然只有 1 次访问数据库,并且仍然只有 selects 所需的列子集,而不是所有列.
你说得对,你应该 select 只使用你实际计划使用的属性,从而将尽可能少的数据传输到你的本地进程。
LINQ 知道两种语句:构成查询的语句和将执行查询的语句。作曲家是 return IQueryable<...>
(或 IEnumerable<...>
)的 LINQ 方法,执行者是 return 和 IQueryable
,但 TResult
。例如 ToList
、FirstOrDefault
、Any
、Max
、...
你应该始终确保执行器是你语句的最后一个,除非你绝对确定执行器后面的语句不会限制数据量。
db.Users.Select(user => new UserVm
{
...
FirstEnrolMentName = user.Enrolments
.OrderBy(enrolment => enrolment.StartDate)
.FirstOrDefault()
.EnrolmentName,
});
我想知道如果您有一个没有任何 Enrolments
的用户,这是否也有效。我的第一个猜测是 FirstOrDefault
会 return 为空,因此当你想获得 EnrolmentName
ArgumentNullException
另一个问题是您首先 select 一个完整的 Enrolment
,然后您丢弃了除名称之外的所有注册属性。最好只 select 您计划使用的属性,然后使用 FirstOrDefault
:
var result = db.Users.Select(user => new UserVm
{
...
FirstEnrolMentName = user.Enrolments
.OrderBy(enrolment => enrolment.StartDate)
.Select(enrolment => enrolment.EnrolmentName)
.FirstOrDefault(),
});