Сделайте несколько запросов к основным таблицам базы данных с помощью LINQ

Я использую Entity framework для управления всеми операциями с базой данных.

На одном конкретном экране моего приложения мне нужно получить данные из многих главных таблиц, которые не связаны друг с другом. В коде С#, если я запрашиваю каждую таблицу отдельно, это занимает много времени и более 10 запросов, которые нельзя объединить.

Есть ли вариант, где я могу объединить их, чтобы сделать один вызов базы данных, но при этом продолжать использовать linq.

В настоящее время я делаю

 var master1=await (from p in context.Master1
             select p).ToListAsync()

 var master2=await (from p in context.Master2
             select p).ToListAsync()

 var master3=await (from p in context.Master3
             select p).ToListAsync()

Что такое альтернатива?

Только если вы сможете спроецировать их всех на один и тот же (анонимный) тип. Затем вы можете использовать .Concat. Но почему нельзя объединить более 10 запросов? Если это из-за таймаутов, то 10 запросов за 1 вызов будет еще хуже.

Gert Arnold 15.12.2020 13:56

См. WhenAll: learn.microsoft.com/en-us/dotnet/api/…

JonasH 15.12.2020 14:21
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
95
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

var master1 = (from p in context.Master1
         select p).ToListAsync()

var master2 = (from p in context.Master2
         select p).ToListAsync()

var master3 = (from p in context.Master3
         select p).ToListAsync()

await Task.WhenAll(master1, master2, master3);

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

Код продолжится только после WhenAll, когда все задачи будут завершены.

Ответ принят как подходящий

Первый шаг — очистить поиск данных только от того, что необходимо. Вызов, который запрашивает 10 несвязанных таблиц, звучит как плохой дизайн. Если это случай, когда вы получаете 10-кратные запросы, рассмотрите возможность рефакторинга дизайна, чтобы они запрашивались меньшими партиями асинхронно (т. е. Ajax) по мере загрузки страницы, а не все сразу.

Что касается загрузки данных, используйте проекцию, а не выборку сущностей. Часто, когда я вижу подобный код, первое, что я ищу, — это штрафы за ленивую загрузку. Это были бы случаи, когда я вижу что-то столь же невинное, как:

var viewModel = new SearchViewModel();

var products = await context.Products.ToListAsync();
viewModel.Products = products;

// ... repeat for other lookups...

return View(viewModel);

Это вызывает тревогу.

  1. Сериализация сущностей будет "касаться" свойств навигации, что приведет к ленивой загрузке.
  2. Даже если свойств навигации нет, нужны ли нам все поля сущностей?
  3. async не серебряная пуля производительности.

Для пунктов 1 и 2: При загрузке данных для возврата к представлению используйте проекцию, чтобы избежать неожиданностей отложенной загрузки и свести к минимуму объем данных, передаваемых как из БД, так и клиенту. Ленивая загрузка может сделать вызовы сервера смехотворно медленными, когда отдельный запрос отлаживает и выполняется быстро, но вы ждете от многих секунд до даже минут, прежде чем страница вернется. Подключение SQL Profiler к базе данных покажет, что после выполнения метода сотни, если не тысячи дополнительных запросов попадают в базу данных помимо 10 или около того, которые вы первоначально вызвали. Это сериализатор, «касающийся» свойств навигации, и это значительно медленнее, чем если бы вы загружали все данные с нетерпением. Решением этих проблем является проекция:

var viewModel = new SearchViewModel();

var products = await context.Products
    .Select(x => new ProductSummaryViewModel
    {
        ProductId = x.ProductId,
        Name = x.Name
    }).ToListAsync();
viewModel.Products = products;

// ... repeat for other lookups...

return View(viewModel);

Вы можете упростить это еще больше, используя Automapper и его метод ProjectTo вместо Select, который работает с EF IQueryable. Projection позволяет избежать неожиданностей отложенной загрузки и строит запросы, которые возвращают только те данные, которые вам нужны.

Для пункта № 3: async не ускоряет операции/вызовы, во всяком случае, делает их немного медленнее. Что он делает, так это делает код вашего сервера более отзывчивым, пока он занят получением более крупных операций. Слишком часто я вижу код, структурированный так, как будто async — это решение по принципу «все или ничего». У него есть свое применение, но его следует использовать экономно там, где он может принести наибольшую пользу. Асинхронное получение небольших наборов или отдельных записей по идентификаторам не приносит никакой пользы. Если операция выполняется не более, чем, скажем, 250 мс и не будет вызываться с очень высокой частотой на массивном многоядерном микросервисном сервере, я, честно говоря, не стал бы вводить накладные расходы на async.

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

Другие вопросы по теме