Рубрики
Без рубрики

Равенство сущностей JPA

Узнайте о равенстве сущностей в JPA.

Автор оригинала: Andre Browne.

1. Обзор

В этом уроке мы рассмотрим обработку равенства с объектами сущностей JPA.

2. Соображения

В общем, равенство просто означает, что два объекта являются одинаковыми. Однако в Java мы можем изменить определение равенства, переопределив методы Object.equals() и Object.hashCode () . В конечном счете, Java позволяет нам определить, что значит быть равными. Но сначала нам нужно кое-что обдумать.

2.1. Коллекции

Коллекции Java группируют объекты вместе. Логика группировки использует специальное значение, известное как хэш-код, для определения группы объекта.

Если значение, возвращаемое методом hashCode () , одинаково для всех сущностей, это может привести к нежелательному поведению. Допустим , наш объект entity имеет первичный ключ, определенный как id , но мы определяем наш метод hashCode() как:

@Override
public int hashCode() {
    return 12345;
}

Коллекции не смогут различать разные объекты при их сравнении, потому что все они будут иметь один и тот же хэш-код. К счастью, решить эту проблему так же просто, как использовать уникальный ключ при генерации хэш-кода. Например, мы можем определить метод hashCode () , используя ваш id :

@Override
public int hashCode() {
    return id * 12345;
}

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

2.2. Переходные Сущности

Вновь созданные объекты сущностей JPA, не имеющие связи с контекстом персистентности , считаются находящимися в переходном состоянии . Эти объекты обычно не имеют заполненных членов @Id . Поэтому, если equals() или hashCode() используют id в своих вычислениях, это означает, что все переходные объекты будут равны, потому что их id s будут все null . Не так много случаев, когда это желательно.

2.3. Подклассы

Подклассы также являются проблемой при определении равенства. Обычно классы сравниваются в методе equals () . Поэтому включение метода getClass() поможет отфильтровать подклассы при сравнении объектов на равенство.

Давайте определим метод equals () , который будет работать только в том случае, если объекты принадлежат к одному классу и имеют один и тот же id :

@Override
public boolean equals(Object o) {
    if (o == null || this.getClass() != o.getClass()) {
        return false;
    }
    return o.id.equals(this.id);
}

3. Определение равенства

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

3.1. Никаких Переопределений

По умолчанию Java предоставляет методы equals() и hashCode() в силу того, что все объекты нисходят из класса Object . Поэтому самое простое, что мы можем сделать, – это ничего не делать. К сожалению, это означает, что при сравнении объектов, чтобы считаться равными, они должны быть одинаковыми экземплярами, а не двумя отдельными экземплярами, представляющими один и тот же объект.

3.2. Использование ключа базы данных

В большинстве случаев мы имеем дело с сущностями JPA, которые хранятся в базе данных. Обычно эти сущности имеют первичный ключ, который является уникальным значением. Поэтому все экземпляры этой сущности, имеющие одинаковое значение первичного ключа, равны. Таким образом, мы можем переопределить equals () , как мы сделали выше для подклассов, а также переопределить hashCode () , используя только первичный ключ в обоих.

3.3. Использование Бизнес-ключа

В качестве альтернативы мы можем использовать бизнес-ключ для сравнения сущностей JPA. В этом случае ключ объекта состоит из членов сущности, отличных от первичного ключа. Этот ключ должен сделать сущность JPA уникальной. Использование бизнес-ключа дает нам тот же желаемый результат при сравнении сущностей без необходимости в первичных ключах или ключах, генерируемых базой данных.

Допустим, мы знаем, что адрес электронной почты всегда будет уникальным, даже если это не поле @Id . Мы можем включить поле электронной почты в методы hashCode() и equals() :

public class EqualByBusinessKey {

    private String email;

    @Override
    public int hashCode() {
        return java.util.Objects.hashCode(email);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (obj instanceof EqualByBusinessKey) {
            if (((EqualByBusinessKey) obj).getEmail().equals(getEmail())) {
                return true;
            }
        }

        return false;
    }
}

4. Заключение

В этом уроке мы обсудили различные способы обработки равенства при написании объектов сущностей JPA. Мы также описали соображения, которые мы должны учитывать при выборе подхода. Как всегда, полный исходный код можно найти на GitHub .