контекстное включение иногда возвращает элементы списка в произвольном порядке - PullRequest
0 голосов
/ 17 апреля 2019

В моем веб-приложении ASP.Core 2.1 у меня есть 3 модели, профиль с множеством счетов, счета с множеством статусов счетов

Я получаю их из БД, например,

_context.Invoices
.Include(st => st.InvoiceStatuses)
.FirstOrDefault(iv => iv.Id == invoiceId);

или иногда

_context.Invoices
.Include(pr => pr.Profile)
.Include(st => st.InvoiceStatuses)
.FirstOrDefault(iv => iv.Id == invoiceId);

Исходя из этого, я ожидаю получить конкретный счет-фактуру и все связанные с ней InvoiceStatuses в том порядке, в котором они были созданы (порядок индекса Db, обязательно). В большинстве случаев это действительно так.Однако иногда я добавляю новую запись счета-фактуры и исходное состояние счета-фактуры, и только некоторые из счетов-фактур имеют связанный список статусов счетов-фактур в случайном / неожиданном порядке.например, индекс 10 12 18 16

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

Было бы проще, если бы проблема возникала постоянно, но если вы удаляете запись (иногда требуется пара записей).Затем вы можете продолжить и добавить несколько записей, прежде чем проблема может снова появиться.

У меня возникает та же проблема при возврате всех Invoices.ToList () и каждого из них. Включите связанные данные, но пытался сосредоточиться насначала самый простой сценарий.

Я не включил LazyLoading или использовал виртуальные ключевые слова, но не уверен, имеет ли это значение.

1 Ответ

0 голосов
/ 17 апреля 2019

Продолжить с моего комментария ....

First / FirstOrDefault всегда следует указывать в предложении OrderBy, если вам не важно, какой из них вы получите.

Заказ в целом - это проблема отображения и бизнес-логики. Сущности - это представление данных.

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

var invoice = _context.Invoices.OrderBy(x => x.Id)
    .Select(x => new InvoiceViewModel
    {
       Id = x.Id,
       // ... Fields the view needs to know about
       InvoiceStatuses = x.InvoiceStatuses.OrderBy(s => s.Id)
           .Select(s => s.StatusText)
           .ToList()
    }).FirstOrDefault();

Таким образом, что-то вроде этого использовало бы Invoice OrderBy, чтобы найти первый применимый Счет-фактуру (по порядку идентификаторов), а затем выбрать интересующие нас поля в модели представления. Для статусов счетов-фактур он упорядочивает их по их идентификатору и выбирает StatusText, чтобы обеспечить просмотр списка статусов в виде строк. В качестве альтернативы вы можете выбрать InvoiceStatusViewModel для возврата текста состояния, идентификатора состояния и т. Д. В зависимости от того, что вы хотите просмотреть.

В качестве альтернативы, если вы выбираете данные, которые будут использоваться на месте для некоторой бизнес-логики, вам не нужно объявлять классы модели представления, просто используйте анонимные типы:

var invoice = _context.Invoices.OrderBy(x => x.Id)
    .Select(x => new 
    {
       x.Id,
       // ... Fields the view needs to know about
       InvoiceStatuses = x.InvoiceStatuses.OrderBy(s => s.Id)
           .Select(s => new 
           {
               s.Id,
               s.StatusText
           })
           .ToList()
    }).FirstOrDefault();

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

Техника использования .Select() для уменьшения результатов помогает привести к более эффективным запросам, поскольку вы можете использовать все формы агрегатных методов, так что вместо того, чтобы возвращать все и затем писать логику для итерации, вы можете использовать Max, Min, Sum, Any и т. Д. Для создания более эффективных запросов, которые выполняются быстрее и возвращают меньше данных по сети.

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