Добрый день!
Помогите, пожалуйста, разобраться с проблемой
Есть две сущности: MainEnitiy и SubEntity (связанные по Composition). При этом у SubEntity есть поле previousSubEntity (Association на SubEntity (на себя же) MtO optional)
Есть экран MainEntityEdit, содержащий вложенную таблицу со списком SubEnitiy.
Проблема воспроизводится вот так:
Ввожу список Sub entities, сохраняю, потом еще раз редактирую и привожу к подобному виду (они связаны по цепочке). Сохраняю.
Захожу снова и пытаюсь по очереди эти SubEntity отредактировать: сначала Sub1, который ни с кем не связан:
Затем пытаюсь отредактировать Sub2, который имеет ссылку на Sub1:
После нажатия кнопки OK вижу следующее:
Этот Sub2 сам отредактировался нормально, но при этом затёр мне изменения, внесенные в Sub1. Если потом отредактировать Sub3, то при этом точно так же затрутся изменения для Sub2
Почему они так со мной поступают и как их убедить этого не делать? )
P.S. понимаю, что тут однозначно влияет нахождение колонки Previous sub entity на экране. Если ее убрать (хотя бы visible=false), то всё нормально, изменения не затираются CompositionIssue.zip (99.0 КБ)
Есть две сущности: MainEnitiy и SubEntity (связанные по Composition).
Если это композиция, то строки с SubEntity сохраняются в БД только при сохранении основной сущности MainEnitiy. И по сути у вас контексты экранов редактирования MainEnitiy и SubEntity повязаны между собой.
На экран редактирования MainEnitiy читается начальное состояние строк SubEntity, включая ссылку на предыдущий экземпляр SubEntity.
Потом вы с экрана MainEnitiy открываете на редактирование строку композиции с Sub1, вносите ее изменения.
Но изменения в БД не сохраняются сохранения данных всего экрана редактирования MainEnitiy. Пока все это просто лежит в контексте экрана.
Потом вы редактируете вторую строку композиции. А в ней у вас в атрибуте previousSubEntity лежит старый экземплярSub1.
В результате, в контексте экрана MainEnitiy после редактирования второй строки, ранее измененный экземпляр Sub1 заменяется старым.
Если в SubEntity атрибут previousSubEntity сделать Ассоциацией - ваш экран заработает без дополнительных изменений. Потому что при каждом редактировании строки с SubEntity данные будут камититься в БД и обновляться в контексте экрана.
Но вообще, на экране редактирования впрямую подтягивать через FetchPlan такого рода ссылки на самого себя это “не есть хорошо”. Есть шанс получить и более мутные проблемы.
Кэш - он попой беспощадный
Большое спасибо за ответ!
Но не совсем понимаю, что имеется в виду
Если в SubEntity атрибут previousSubEntity сделать Ассоциацией - ваш экран заработает без дополнительных изменений. Потому что при каждом редактировании строки с SubEntity данные будут камититься в БД и обновляться в контексте экрана.
В SubEntity атрибут previousSubEntity и так Ассоциация.
open class SubEntity {
<...>
@JoinColumn(name = "MAIN_ENTITY_ID", nullable = false)
@NotNull
@ManyToOne(fetch = FetchType.LAZY, optional = false)
var mainEntity: MainEntity? = null
@JoinColumn(name = "PREVIOUS_SUB_ENTITY_ID")
@ManyToOne(fetch = FetchType.LAZY)
var previousSubEntity: SubEntity? = null
Это для MainEntity все SubEntity композиция.
open class MainEntity {
<...>
@OnDelete(DeletePolicy.CASCADE)
@Composition
@OneToMany(mappedBy = "mainEntity")
var subEntities: MutableList<SubEntity> = NotInstantiatedList()
Имелось в виду для MainEntity их сделать ассоциацией или что?
И если все-таки связь между MainEntity и SubEntity оставить композицией (SubEntity это что-то вроде позиций заказа, которые без своей шапки MainEntity нежизнеспособны), то, получается, на экране редактирования SubEntity связь между двумя SubEntity устанавливать нежелательно? Может быть, дадите какие-то рекомендации по методике, где и как тогда это лучше делать? Заранее спасибо)
Я имел в виду в сущности MainEntity атрибут SubEntity сделать не Композицией, а Ассоциацией.
Если по сути связь между MainEntity и SubEntity это действительно именно Композиция, тогда и интерфейс надо продумывать исходя из этого.
Сложно рекомендовать что-то конкретное не понимая конкретного бизнес-сценария для пользователя.
Если не отказываться от Композиции , то можно вместо стандартного действия edit сделать свою копку или действие и там, вызывая для строки экран редактирования SubEntity , после его закрытия по кнопке ОК, камитить данные экрана MainEntity.
Но в этом случае идейный смысл использования именно композиции слегка теряется.
Можно на экране редактирования MainEntity исключить ссылочный атрибут subEntities из загрузки в FetchPlan.
А для отображения неких сведений о SubEntity на экране редактирования MainEntity сделать генерируемую колонку и в нее подтягивать для отображения в UI тот же instanceName через dataManager.
В этом случае, у вас на экране редактирования MainEntity в контекст экрана не будут грузиться экземпляры SubEntity и все должно быть хорошо
Как я понимаю в таком случае просто не происходит перезагрузка данных при открытии редактора и как следствие в поле previousSubEntity ставится обновленная версия, а не подгруженная из бд.
Да, кстати, в Cuba это точно помогало в подобных случаях.
Но придется помнить о том, что надо в этом надо содержать fetchPlan этих атрибутов на разных экранах идентичным.
Как-то мы в итоге стали стараться избегать этого на корню генерируемыми колонками или неперсистентными атрибутами.