我的上下文模型有几个相关的表:
CREATE TABLE "CarSystem"."Reads" (
"ReadId" UUID PRIMARY KEY,
. . .
);
CREATE TABLE "CarSystem"."Alarms" (
"AlarmId" UUID PRIMARY KEY DEFAULT UUID_GENERATE_V4(),
"ReadId" UUID NOT NULL REFERENCES "CarSystem"."Reads" ( "ReadId" ),
. . .
);
还有其他专栏,但它们并不重要。 Reads表和Alarms表之间存在从零到多的关系。 “读取”表中每行的“警报”表中可以有任意数量的行,从零开始。
我有这个数据库结构的实体框架模型。我还为Reads表中的行提供了一个ViewModel对象。我希望ViewModel对象具有一个名为HasAlarms的布尔属性。如果“读取”表中的行的“警报”表中至少有一行,则此属性将设置为true。
我的数据访问层中有一个函数,它应该返回一组Read ViewModel对象,这些对象都符合一组条件。我不确定如何构造查询来设置HasAlarms属性。我只想去数据库一次,我想在数组中为Reads表中的每一行输入一个条目。
现在我正在进行两个数据库查询,一个用于检索所有的Reads,另一个用于检索所有的Alarms:
IQueryable<Read> query = from read in context.Reads
where SomeCondition
select read;
Alarm[] alarms = ( from read in query
join alarm in context.Alarms on read.Readid equals alarm.ReadId
select alarm ).ToArray();
ReadViewModel[] result = ( from read in query
select new ReadViewModel {
ReadId = read.ReadId,
. . .
HasAlarms = alarms.Where( a => a.ReadId == read.ReadId ).Any(),
. . .
} ).ToArray();
这样可行,但效率很低,因为我在数据库中访问了两次,一次是在Reads表中检索行,一次是获取警报。
有没有办法构建这个查询,所以它只能访问一次数据库?
贝
@Craig Stuntz:
我要做的是加快应用程序中响应报告请求的数据加载速度。这是一个WPF应用程序,我需要尽快加载数据以改善用户体验。重要的是尽可能少地访问数据库,否则应用程序似乎会爬行。
ReadViewModel对象包含映射到表中列的属性,以及一些嵌套对象,这些对象可以作为列存储在同一个表中,也可以存储在几个相关表中的行中。这是一个复杂的结构,如果我尝试使用一个IQueryable创建View Model对象,则Entity Framework会抱怨。就是这样:
ReadViewModel[] reads = ( from read in context.Reads
join alarm in context.Alarms on read.ReadId equals alarm.ReadId
where SomeCondition
select new ReadViewModel { ... } ).ToArray();
抛出一个异常,表示Entity Framework无法创建其中一个嵌套类型的常量。
如果我将数据检索到实体对象的数组中,然后使用Linq创建View Model对象,一切正常。但是,我必须多次访问数据库才能获得所有内容。但是,如果我使用这些查询检索所有数据,它比让Entity Framework返回并查询每行的额外数据要快得多,这就是当我按照您的推荐方式执行时所发生的情况。还有一个复杂的问题就是必须使用Alarms表进行左外连接以便搞乱。
我发现如果我首先检索实体对象的数组,而不是在初始行程之外为每行进行一次旅行,我总共可以进行2或3次旅行。它比进行n + 1或n + 2次旅行要快得多。我只是试图看看是否有一种方法可以让Entity Framework在一个数据库调用中完成所有操作,如果我自己编写SQL,我可以很容易地做到这一点。如果Read的Alarms表中至少有一行,我只需添加一个为HasAlarms返回0或1的列。
答案 0 :(得分:3)
使用模型中的导航/关系。 It's usually wrong to spell out joins in L2E
ReadViewModel[] result = ( from read in context.Reads
where SomeCondition
select new ReadViwModel
{
ReadId = read.ReadId,
// . . .
HasAlarms = read.Alarms.Any(),
// . . .
} ).ToArray();