2011-12-29 4 views
1

Моей контекстная модель имеет несколько связанных таблицы:Нужна помощь построение 4 запроса Entity Framework

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 существует соотношение «0». В таблице 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.

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

Тони

@Craig Stuntz:

То, что я пытаюсь сделать, это ускорить скорость, с которой загружаются данные в моем приложении в ответ на запрос отчета. Это приложение 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, чтобы все испортить.

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

ответ

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

Plesase см. Мое редактирование оригинального вопроса. –

+0

Запрос, который я дал вам, получает весь результат в одном раунде. –

Смежные вопросы