Комментарии 10
Выполнение sql из контруктора, в новом контексте и коннекшене, при всем уважении, выглядит дико, особенно в момент материализации, это приглашение к проблемам само по себе.
Добрый день. Первоначально проблема возникла при работе двух независящих друг от друга плановых задач. Пример в статье с использованием конструктора моделирует эту ситуацию и позволяет ее стабильно воспроизводить.
Думаю, именно пример из этого тикета это основная причина по которой он не пофикшен до сих пор (дикий код, рейс, нет тест репо == отложим до лучших времен). Ситуация, как мне кажется, довольно редкая, если не писать странный код, обычно выгружают из базы через проекции то, что надо, или только свой агрегат через инклюды, на каком реальном кейзе это воспроизвелось?
В нашем случае выполнялись две плановые задачи:
отправка опубликованных заказов в офисы
отправка опубликованных заказов в бухгалтерию
Первая задача не модифицировала заказы, только читала.
Вторая задача выполняла изменение одного поля (ConfirmationId).
Во время модификации поля во второй задаче, происходило чтение в первой, что привело к тому, что часть данных не подгрузилась.
Модификация во второй задаче не должна была влиять на чтение в первой задаче, так как она меняла родительское поле которое не влияет на загрузку детей.
В EFC 2.0 проблем в таком кейсе не было.
В том же issue недавно появился новый пример, в котором не используется конструктор и соответственно не затрагивается материализация.
https://github.com/torutek/EfTest/blob/master/EfTest/EfTestContext.cs#L53
Но это тоже своеобразный хак
Дополню, что в нашем случае:
задача отправки заказов в офисы прочитала заказы (Order)
задача отправки заказов в бухгалтерию поменяла поле в Order
задача отправки заказов в офисы прочитала блюда из заказов (DishInOrder) - вторым, разделенным запросом
И вышло так что в пункте 3 для некоторых заказов не подгрузился список блюд
Это как раз то, чего они пишут не делать в документации со сплитом - не читать конкуренто изменяемые данные, пусть даже можно было бы пофиксить этот конкретный рейс. Делать так плохо в любом случае (сегодня поменяли одно поле, завтра два, результат не предсказуемый). И зачем выгружать изменяемую часть, зная что она может поменяться? И неужели для отправки в офис и бухгалтерию требуются все поля и все вложенные сущности?
Я согласен с вами по поводу проблем в применяемом подходе.
Передо мной стояла задача обновить EFC.
При обновлении я включил SplitQuery, так как без него были проблемы, и не видел в этом чего-то плохого, ведь я таким образом не менял поведение, которое было в EFC 2.0.
Как оказалось, в новой версии EFC механизм SplitQuery стал нести больше опасности чем раньше. И я пришел к выводу, что без транзакций нет смысла его использовать. Ведь сегодня запросов на запись может не быть, а завтра они появятся и про SplitQuery никто не вспомнит.
Так же в приведенном выше случае нет проблем с точки зрения БД. Согласованность не нарушается.
Если выполнить сгенерированные EFC запросы не в EFC (а например на голом ADO.NET), то проблемы не будет.
Поэтому я не воспринял предупреждение из документации, как относящееся к внутренней логике EFC соединения детей с родителями, о чем собственно сказал в статье
While most databases guarantee data consistency for single queries, no such guarantees exist for multiple queries. If the database is updated concurrently when executing your queries, resulting data may not be consistent. You can mitigate it by wrapping the queries in a serializable or snapshot transaction, although doing so may create performance issues of its own. For more information, see your database's documentation.
https://github.com/dotnet/efcore/issues/33826
первая ссылка
повторил
написал нормальные модели, а не это стыдобище в примере
дало тот же результат что и ожидали
Проблемы при использовании разделенных запросов в Entity Framework Core 8