Является ли Queryable правильным способом получения элементов из сервиса? - PullRequest
0 голосов
/ 09 июля 2019

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

На данный момент я пытался не возвращать IEnumerable, но Iqueryable и создавать выражение Where в методах, которые вызывают службу, но я не думаю, что это правильный способ сделать это. Конечно, если где-то предложение Where дублируется, я пытаюсь переместить дублированный код в сервис и использовать Iqueryable, созданный ранее.

OLD:

public async Task<IEnumerable<Element>> GetElementsByIds(List<int> elementsIds)
        {
            var elements = await _context.Elements
                .Include(e => e.ElementCategories)
                .Include(e=>e.ElementSth)
                .Where(e => elementsIds.Contains(e.Id))
                .ToListAsync();

            if (!elements.Any())
            {
                throw new NotFoundException(nameof(Element), elementsIds);
            }

            return elements;
        }

        public async Task<IEnumerable<Element>> GetElementsPerCategory(string categoryName)
        {
            var elements = await _context.Elements
                .Include(e => e.ElementCategories)
                .Include(e=>e.ElementSth)
                .Where(c=>c.Category.Name == categoryName)
                .ToListAsync();

            if (!elements.Any())
            {
                throw new NotFoundException(nameof(Element), elementsIds);
            }

            return elements;
        }

ТЕПЕРЬ:

public async Task<IQueryable<Element>> GetElementsByIds(List<int> elementsIds)
        {
            var elements = _context.Elements
                .Include(e => e.ElementCategories)
                .Include(e=>e.ElementSth);

            return elements;
        }

Я хочу реорганизовать сервис и создать будущие сервисы лучше. Есть ли у вас опыт с проблемой?

1 Ответ

1 голос
/ 09 июля 2019

Прямой доступ к IQueryable<> - это совсем другое, поскольку он в основном позволяет делать что-либо с базой данных. В зависимости от того, что на самом деле запрашивается, даже ваши .Include() звонки могут игнорироваться.

Предоставление запрашиваемых во внутренних службах - хороший способ написать очень эффективные запросы (поскольку тогда они просто получат то, что им действительно нужно). Для менее внутренних или общедоступных API я бы порекомендовал не выставлять запрос напрямую, чтобы сохранить контроль.

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

public async Task<IEnumerable<Element>> GetElementsByIds(List<int> elementsIds)
{
    return await GetElementsInternal(_context.Elements.Where(e => elementsIds.Contains(e.Id)));
}

public async Task<IEnumerable<Element>> GetElementsPerCategory(string categoryName)
{
    return await GetElementsInternal(_context.Elements.Where(e => e.Category.Name == categoryName));
}

private async Task<IEnumerable<Element>> GetElementsInternal(IQueryable<Element> queryable)
{
    var elements = queryable
        .Include(e => e.ElementCategories)
        .Include(e => e.ElementSth)
        .ToListAsync();

    if (!elements.Any())
    {
        throw new NotFoundException(nameof(Element), elementsIds);
    }

    return elements;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...