Нужна помощь в создании запроса Entity Framework 4 - PullRequest
1 голос
/ 29 декабря 2011

В моей контекстной модели есть пара связанных таблиц:

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 существует связь от нуля до многих. В таблице Alarms может быть любое количество строк для каждой строки в таблице Reads, от нуля до.

У меня есть модель Entity Framework для этой структуры базы данных. У меня также есть объект ViewModel для строк в таблице Reads. Я хочу, чтобы объект ViewModel имел логическое свойство с именем HasAlarms. Это свойство должно иметь значение true, если в таблице Alarms есть хотя бы одна строка для строки в таблице Reads.

У меня есть функция на уровне доступа к данным, которая должна возвращать массив объектов Read ViewModel, которые соответствуют набору критериев. Я не уверен, как построить запрос, чтобы установить свойство HasAlarms. Я хочу зайти в базу данных только один раз, и мне нужна одна запись в массиве для каждой строки в таблице Reads.

Сейчас я делаю два запроса к базе данных, один для получения всех Чтений, а другой для получения всех Тревог:

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, и один раз, чтобы получить Alarms.

Есть ли способ создать этот запрос, чтобы он попадал в базу данных только один раз?

Tony

@ Крейг Штунц:

Я пытаюсь ускорить загрузку данных в мое приложение в ответ на запрос отчета. Это приложение WPF, и мне нужно, чтобы данные загружались как можно быстрее, чтобы улучшить взаимодействие с пользователем. Важно совершить как можно меньше поездок в базу данных, иначе приложение будет сканироваться.

Объект ReadViewModel состоит из свойств, которые сопоставляются со столбцами в таблице, а также с парой вложенных объектов, которые либо хранятся в виде столбцов в одной и той же таблице, либо в виде строк в нескольких связанных таблицах. Это сложная структура, и Entity Framework жалуется, если я пытаюсь создать объекты View Model с одним IQueryable. То есть что-то вроде:

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 не может создать константу одного из вложенных типов.

Если я извлекаю данные в массивы объектов Entity, а затем создаю объекты View Model с помощью Linq, все работает. Но затем мне нужно совершить более одной поездки в базу данных, чтобы получить все. Однако если я получу все данные с помощью этих запросов, это будет намного быстрее, чем позволить Entity Framework вернуться и запросить дополнительные данные для каждой строки, что и происходит, когда я делаю это так, как вы рекомендуете. Существует также сложность необходимости сделать левое внешнее соединение с таблицей Alarms, чтобы все испортить.

Я обнаружил, что если я сначала получу массивы объектов сущности, вместо того, чтобы совершать одну поездку для каждой строки в дополнение к первоначальной поездке, я могу сделать в общей сложности 2 или 3 поездки. Это гораздо быстрее, чем совершать n + 1 или n + 2 поездки. Я просто пытался понять, есть ли способ заставить Entity Framework сделать все это за один вызов базы данных, что я мог бы легко сделать, если бы сам писал SQL. Мне просто нужно добавить столбец, который возвращает 0 или 1 для HasAlarms, если в таблице Alarms есть хотя бы одна строка для чтения.

1 Ответ

3 голосов
/ 29 декабря 2011

Используйте навигацию / отношения в вашей модели. Обычно неправильно указывать соединения в L2E .

ReadViewModel[] result = ( from read in context.Reads
                           where SomeCondition
                           select new ReadViwModel
                           {
                               ReadId = read.ReadId,
                               // . . .
                               HasAlarms = read.Alarms.Any(),
                               // . . .
                           } ).ToArray();    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...