需要帮助构建Entity Framework 4查询

时间:2011-12-29 17:11:32

标签: c# entity-framework-4

我的上下文模型有几个相关的表:

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的列。

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();