Я прочитал DDD Evans и экспериментирую с составным проектом корневого репозитория с использованием C # и Entity Framework 4.1 + LINQ.
Однако я обеспокоен фактическими запросами, которые отправляются вБД.Я использую SQL 2008 R2 и запускаю SQL Profiler, чтобы проверить, что делает БД в ответ на код LINQ.
Рассмотрим простой дизайн с двумя сущностями с Person и EmailAddress.Один человек может иметь от нуля до нескольких адресов электронной почты, а адрес электронной почты должен иметь ровно одного человека.Person - это совокупный корень, поэтому не должно быть хранилища для адресов электронной почты.Адреса электронной почты следует выбирать из репозитория Person (согласно DDD Evans).
Для сравнения, у меня есть временный репозиторий для адресов электронной почты.Следующая строка кода:
var emailString = "someone@somewhere.com";
var emailEntity = _tempEmailRepository.All.SingleOrDefault(e =>
e.Value.Equals(emailString, StringComparison.OrdinalIgnoreCase));
... выполняет красивый чистый запрос SQL в соответствии с профилировщиком:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[PersonId] AS [PersonId],
[Extent1].[Value] AS [Value],
[Extent1].[IsDefault] AS [IsDefault],
[Extent1].[IsConfirmed] AS [IsConfirmed],
FROM [dbo].[EmailAddress] AS [Extent1]
Я могу выбрать электронное письмо из репозитория пользователя, с помощьюследующий код:
var emailEntity = _personRepository.All.SelectMany(p => p.Emails)
.SingleOrDefault(e => e.Value.Equals(emailString,
StringComparison.OrdinalIgnoreCase))
Это возвращает мне ту же сущность во время выполнения, но с различными командами, отображаемыми в SQL Profiler:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[FirstName] AS [FirstName],
[Extent1].[LastName] AS [LastName],
FROM [dbo].[Person] AS [Extent1]
В дополнение к вышеуказанному запросу, который выбираетот Person есть несколько событий "RPC: Завершено", по одному для каждой строки EmailAddress в БД:
exec sp_executesql N'SELECT
[Extent1].[Id] AS [Id],
[Extent1].[PersonId] AS [PersonId],
[Extent1].[Value] AS [Value],
[Extent1].[IsDefault] AS [IsDefault],
[Extent1].[IsConfirmed] AS [IsConfirmed],
FROM [dbo].[EmailAddress] AS [Extent1]
WHERE [Extent1].[PersonId] =
@EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=1
exec sp_executesql N'SELECT
[Extent1].[Id] AS [Id],
[Extent1].[PersonId] AS [PersonId],
[Extent1].[Value] AS [Value],
[Extent1].[IsDefault] AS [IsDefault],
[Extent1].[IsConfirmed] AS [IsConfirmed],
FROM [dbo].[EmailAddress] AS [Extent1]
WHERE [Extent1].[PersonId] =
@EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=2
Мой тестовый БД содержит 14 строк в dbo.EmailAddress, и существует 14 различных RPC: Завершенные вызовы, каждый из которых имеет свое значение @ EntityKeyValue1.
Я предполагаю, что это плохо для производительности SQL, поскольку, поскольку таблица dbo.EmailAddress получает больше строк, большее количество этих RPC будет вызываться в БД,Есть ли другой лучший подход к использованию агрегированных корневых репозиториев DDD с EF 4.1 + LINQ?
Обновление: решено
Проблема заключалась в том, что свойство All возвращало IEnumerable<TEntity>
.После того, как это было изменено на IQueryable<TEntity>
, LINQ включился и выбрал весь человек + электронные письма в одном кадре.Однако мне пришлось включить в цепочку .Include (p => p.Emails), прежде чем возвращать IQueryable из All.