Как запросить связанные сущности (отношение 1: N) в структуре сущностей - PullRequest
1 голос
/ 30 марта 2011

Как лучше получить связанные сущности в сценариях , например: {диаграмма классов здесь} ?
Я написал два способа (обратите внимание также на разницу в диаграмме классов) ... У проекта есть свойство с ICollection of Tasks, но у Member нет. Оба способа работают, и я хотел бы знать, какой из них правильный (лучше / быстрее). Или, если нет ничего хорошего, то каков правильный путь в этих простых сценариях?
Код:

    using (var db = new EntitiesContext())
        {
            // way A
            Project project = db.Projects.Include("Tasks").First();
            List<Task> projectTasks = project.Tasks.ToList();
            count = projectTasks.Count;

            // way B
            Member member = db.Members.First();
            IQueryable<Task> memberTasks = from t in db.Tasks
                                           where t.AssignedTo.Id == member.Id
                                           select t;
            count = memberTasks.Count();
        }

Сначала я использую код EF 4.1.
Кстати: не беспокойтесь о результате (получить счет) слишком много. Это всего лишь часть тестового кода, я, конечно, хотел бы в будущем запросить больше полезной информации.

Ответы [ 5 ]

2 голосов
/ 30 марта 2011

При выполнении этих запросов ваши узкие места производительности обычно попадают в одну из двух категорий:

  1. Получение слишком большого количества данных, которые вам не нужны.
  2. Слишком много обращений к базе данных.

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

Ваш второй пример создает второе круговое путешествие для получения заданий. Дополнительное двустороннее взаимодействие вносит дополнительные издержки, но это означает, что в целом будет возвращено меньше дублированных данных. Одна дополнительная поездка туда и обратно, вероятно, не имеет большого значения, но если вы делаете это для нескольких проектов, вы можете легко получить десятки ненужных поездок туда и обратно.

Таким образом, решение о том, какой путь выбрать, будет действительно уравновешивающим, основываясь на том, как обычно выглядят ваши данные и чего вы действительно от них хотите. В этом конкретном случае вам лучше использовать:

count = db.Tasks.Count(t => t.AssignedTo.Id == db.Members.FirstOrDefault().Id)

..., который создаст один оптимизированный запрос, который просто возвращает счетчик, без лишних данных или дополнительных циклов. Таким образом, вы можете видеть, как ответ на подобные вопросы будет зависеть от того, что именно вы пытаетесь получить из базы данных.

Ответ на комментарий

Если вы пытаетесь получить все задачи, связанные с чем-то, ваш запрос должен содержать только задачи. Есть много способов сделать это:

var memberTasks = db.Tasks.Where(t => t.AssignedTo.Id == memberId).ToList();

или (если вы еще не знаете ID участника):

var memberTasks = db.Tasks.Where(t => t.AssignedTo.[your criterion]))
                      .ToList();

или (если вы хотите, чтобы задачи выполнялись сразу для нескольких участников):

var tasksByMemberId = (from t in db.Tasks
                       where t.AssignedTo.[your criterion])
                       select new {MemberId = t.AssignedTo.Id, t})
                      .ToLookup(e => e.MemberId, e => e.t);

Я мог бы продолжить. Дело в том, что все эти запросы специально выполняют задачи, не беспокоясь о данных участника.

Добавление дополнительного слоя данных тоже ничего не должно изменить:

var projectTasks = db.Tasks.Where(t => t.Iteration.Project.Id == projectId).ToList();
1 голос
/ 30 марта 2011

Оба способа работают, и я хотел бы знать, какой из них правильный (Лучше / быстрее).

Использование Linq to Entities в целом. Навигационные свойства - это то, что нужно - данные объединяются автоматически (если вы используете Include).

Ваш первый запрос не оптимизирован для подсчета, вы можете просто написать:

count = db.Projects.Include("Tasks").First().Tasks.Count();

В противном случае вы загружаете все связанные объекты задачи из БД.

1 голос
/ 30 марта 2011

Метод A является более чистым и приводит к оптимизированному SQL-запросу, извлекающему все связанные данные сразу. Метод B похож на ленивую загрузку связанных данных, когда вам это нужно.

Я предпочитаю A, когда мне нужны данные сейчас, и B, когда я могу даже не получить доступ к связанным данным, если пользователь не предпримет какие-либо действия в программе.

1 голос
/ 30 марта 2011

Я думаю, что эти два нельзя сравнивать, потому что оба примера имеют свое применение. Первый способ - определенно, если у вас есть свойство навигации, потому что в этом случае вы вернете все данные за одну поездку в базу данных. Второй подход полезен, если у вас нет доступных свойств навигации.

0 голосов
/ 30 марта 2011

Почему бы вам не использовать это:

project.Tasks.Load();
...