Репозиторий “два-в-одном”

253
04 февраля 2019, 17:40

Есть некоторый сервис, который дёргает два репозитория (первый - к сущности Order, второй - к сущности OrderPosition) и возвращает уже собранный заказ - Dto объект, в котором лежит и Order и OrderPosition.

public async Task<OderDto> DetailsAsync(int orderId)
{
    var order = await this.OrderRepository.GetAsync(orderId);
    var orderPositions = await this.OrderPositionsRepository.ForOrderAsync(orderId);
    return new OrderDto
    {
       Order = order,
       OrderPosition = orderPositions,
    };
}

Так было устроено приложение, когда оно было собрано на чистом EF - клепаешь себе простенькие Linq-выражения, живёшь не нарадуешься.

Однако когда-то наступает момент, когда некоторые запросы становятся сложными и в приложении появляется Dapper c plain sql запросами. Допустим тот же пример очень хочется переписать избежав двух запросов к базе, всё за раз. И, вместо соединения данных в сервисе прямо в репозитории достаём то, что нам надо:

public async Task<OderDto> GetOderDtoAsync(int orderId)
{
    const string query = @"
        SELECT *
        FROM dbo.Order o
        WHERE 1 = 1
            AND o.Id = @orderId
        SELECT *
        FROM dbo.OrderPosition op
        WHERE 1 = 1
            AND op.OrderId = @orderId
    ";
    var parameters = new
    {
        @orderId = orderId,
    };
    using (var multi = this.Db.QueryMultiple(query, parameters))
    {
        var order = await multi.ReadSingleOrDefaultAsync<Order>();
        var orderPositions = await multi.ReadAsync<OrderPosition>();
        return new OderDto
        {
            Order = order,
            OrderPosition = orderPositions.AsList().AsReadOnly(),
        };
    }
}

(Сервисы конечно в таком подходе редко нужны - только для какой-то сложной обработки выбранных данных, чаще просто излишний слой, тупо передающий данные as is. Но эта экономия числа запросов к базе очень сильно подкупает, да и подобных проблем уже не возникает.)

Вопрос чисто методологический. Можно ли при этом продолжать считать, что используется шаблон Repository или это уже не репозиторий?

У меня так выходит, что это класс совмещает в себе два репозитория и некоторую логику (характерную для сервиса) над возвращёнными объектами, а значит (несмотря на всю дырявость паттерна репозиторий) надо дать ему более подходящее название. Но какое? На что вообще похож данный подход в построении приложения?

Answer 1

Репозиторий - это вполне конкретный паттерн.

Точнее, два разных паттерна:

  1. Классический репозиторий из PoEAA. Тот самый, который Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.

Ваш код не предоставляет доступ доменным объектам в виде коллекции (вы же какие-то DTO наверх выдаете) - значит, это не Repository.

  1. "Репозиторий запросов", который в C# обычно проявляется в виде класса-обертки поверх готовой реализации репозитория (1) в EF, и которы обычно используют ради возможности подменить его на мок при юнит-тестировании BL, и заодно ради предотвращения прорастания IQueryable выше в BL.

У него вроде бы нет определения в каком-нибудь PoEAA, но общий смысл примерно "Инкапсулирует в себе построение LINQ-выражений, изолирует IQueryable от сервисного уровня, позволяя написать на сервисный уровень юнит-тесты". Тоже не ваш случай.

Т.е. у вас был класс, который назывался "Repository", но на самом деле это было обычный Transaction Script с прямой выборкой данных внутри - и вы просто переписали эту выборку данных. Репозитория, в строгом смысле, у вас не было и нет. И он вам, скорее всего, не нужен.

READ ALSO
Как эффективно затереть данные

Как эффективно затереть данные

Задача: повредить файл, для обеспечения невозможности его чтения(И удачного восстановления если его удалить программным способом, на той...

395
Bluetooth LE не обнаруживает устройства

Bluetooth LE не обнаруживает устройства

Делаю попытку обнаружения устройств с помощью Bluetooth LE, сделал как написано в этой библиотеке для Xamarin, однако обнаруженных устройств 0

207
LINQ c# Условие внутри сортировки

LINQ c# Условие внутри сортировки

Сортирую список и нужно указать условие что-то вроде если "поле" == null, то сортируй по "поле2", если нет то сортируй по "поле"Как я понял конструкция...

206
Как правильно обработать строку?

Как правильно обработать строку?

Есть строка, которая может иметь следующий вид, числа в конце строки каждый раз разные:

209