Pull to refresh
35
0
Илья Сазонов @poxvuibr

Software developer

Send message
Вы прячете в деталь реализации неожиданное усложнение .get из мапы до o(n).

Поэтому не надо делать энтити ключами мапы


Пишем типовой поиск всех элементов из соседней коллекции в этой и вот он квадрат.

По перечисленным выше причинам, так делать не надо.


И уже не надо много. Уже тысячах на 10 элементов тормоза будут.

Во-первых, по перечисленным выше причинам на надо делать Set из десяти тысяч энтити. Потому что это приведёт к проблемам.


Во-вторых, десять тысяч элементов на связи OneToMany это много независимо от коллекции, которая используется для их хранения. В таких случаях лучше делать только связь ManyToOne потом выбирать элементы отдельным запросом.


Не надо так софт проектировать.

Я тоже говорю об этом.


Не надо использовать энтити в качестве ключей хешмепа. Не надо использовать что-то кроме id в equals и hashCode. hashCode должен возвращать константу. equals должен вернуть false если хотя бы один id равен null. Это актуально для энтити в которых нет естественного ключа, а суррогатный ключ не известен сразу после вызова конструктора объекта.


Не надо делать OneToMany с большим количеством участников. Это актуально для всех энтити.


Правил ещё много, но эти относятся к теме напрямую.

Ну, утверждать-то можно что угодно

Врядли нас обманывают ))). Я делюсь своим опытом, комментаторы своим. Мне кажется имеет смысл верить, что по крайней мере субъективно у них и правда всё получается понятно и код нормально читается другими людьми

Практикующие такое утверждают, что понятно всем. Я, правда, не поддерживаю эту позицию. Лично я считаю, что надо рефакторить код по мере возникновения вопросов по нему. Как не избегай состояния потока, всё равно ты при разработке периодически в него попадаешь.

Прошу прощения за недостаточную детализацию. Если серьёзно писать на эту тему — комментария не хватит. И вот эту важную деталь, как и многие другие, я не упомянул. Использование коллекций с JPA вообще нетривиальная штука. Мало того, что в некторых случаях надо делать remove а потом add одного и того же объекта, так ещё и надо делать много странных движений для маппинга, если хочешь убрать дополнительные запросы. Плюс надо помнить, что в Hibernate зачастую используется на ArrayList или что-то в этому духе, а какая-нибудь другая структура. Когда я пытаюсь вкратце рассказать, постоянно что-то упускаю.

Это просто особенность реализации HashSet и TreeSet.

Контракт на интерфейс Set гарантирует, что если сделать сначала remove, а потом add, то в коллекции окажется новый объект. Наверное надо было сразу написать про все операции целиком.

В таком случае вы завязываетесь на недокументированное поведение.

Мне кажется нет такого. Какое поведение из того на что я ссылаюсь не документировано?

Именно для того, чтобы объект не менял бакет, hashCode должен возвращать константу

По хорошему движок JPA не должен поместить в контекст две разных энтити, указывающих на одну и ту же строку. Вся штука в том, что нужно держать в одной коллекции несколько энтити, которые есть в контексте, которых ещё в нём нет и не забыть про энтити, которые пока не попали даже в БД.

Чтобы когда кладёшь в Set энтити и там уже есть энтити с таким id, новая энтити вытеснила старую.


Ну и иногда удобно делать arrayList.contains

Ну вот я и говорю, что дерево будет в лучшем случае ))

Если переопределить equals, то проблем с определением быть не должно, даже если одна из сущностей ещё не находится в контексте.

Не совсем. Там получается два разных потока. В одном контекста много. Потом через какое-то время (через пару тройку дней) разработчик входит в другой поток, где он уже забыл контекст и стремится сделать всё как можно более понятным.

Честно говоря не ясен их смысл у мутабельных объектов.

Конкретно в энтити — есть необходимость безопасно добавлять и в Set.


Добавили в сет, потом поменяли?

Да, добавили в сет пока id == null, потом записали в БД и id сгенерировались и при этом сет должен работать корректно.

Вариантов-то всего три: сравнивать по ссылке, сравнивать по id, сравнивать по всем атрибутам. Почему плох третий — автор написал, теперь сравним первые два варианта.

Правильно сравнивать по Id, но добавить условие, что если id ==null, то equals выдаст false. Ну и плюс вернуть константу в hashCode конечно

Это звучит гораздо разумнее, чем превращать HashMap в ArrayList.

HashMap невозможно превратить в ArrayList. В лучшем случае будет дерево.

Проще не создавать никакого поля и использовать equals и hashCode по умолчанию.

Такая позиция существует, но тогда получается, что будут проблемы с пониманием, что две энтити у которых равен id относятся к одной и той же строке в БД

И все равно так не делайте. Это выстрелит через непонятное время.

Вот если написать в hashCode не константу, то да, выстрелит. Не сразу, но обязательно будут плавающие баги.


Ваши хешмапы превратились в тримапы. logn это не очень много, но все равно легко можно написать код который думая что там o(1) внезапно начнет тормозить на пустом месте.

Для этого не надо использовать энтити как ключи в хешмапе. А когда используешь коллекции типа HashSet, надо помнить, что нельзя класть туда много элементов. Но вообще надо просто помнить, что надо делать связи OneToMany в которых много элементов

Никогда не возвращайте из hashCode константу.

За исключением случая, когда речь идёт о hashCode в классе, помечнном аннотацией Entity.


Это бессмысленно,

В случае с Entity это крайне осмысленно, потому что equals должен быть завязан на Id и Entity у которых Id == null должны быть не равны друг другу, чтобы можно было сложить их в Set


поскольку не просто ухудшает производительность хеш-таблиц, но сводит их к массиву.

Не к массиву, а к дереву, но да, сводит. Поэтому Entity не надо делать ключами в HashMap. Что касается коллекций типа Set — когда речь идёт об Entity, там в любом случае нельзя держать много элементов, так что ничего страшного не случится.


Но если вам достаточно массива, почему бы не использовать ArrayList вместо хеш-таблицы?

Обычно так и делают. Но даже в этом случае надо сделать так, чтобы arrayList.contains работал корректно, когда ему отдают Entity с id равным null

Лет пять назад у меня на Хабре был точно такой же диалог ))). Тогда один из участников сказал, что сначала он пишет код в потоке, а потом в потоке же его рефакторит. Чтобы код стал максимально простым и понятным.

Загуглил эти термины — они встречаются только в трудах одного автора.

Это неправда ))). Сепульки — наименование биологческого таксона )))

Information

Rating
Does not participate
Date of birth
Registered
Activity