Спящий равный и прокси

У меня есть один BaseEntity, который абстрагирует свойство id и version. этот класс также реализует хэш-код и равен на основе свойства PK (id).

BaseEntity{

    Long id;
    Long version; 

public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((id == null) ? 0 : id.hashCode());
    return result;
}

public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    BaseEntity other = (BaseEntity) obj;
    if (id == null) {
        if (other.id != null)
            return false;
    } else if (!id.equals(other.id))
        return false;
    return true;
}


}

теперь две сущности A и B расширяют BaseEntity, как показано ниже

A extends BaseEntity{
    `B b`
     B getB(){return b;)
     void setB(B b){this.b=b;}
}

B extends BaseEntity{
}

object b1;
object a1;
a1.set(b1);
session.save(a1) //cascade save;

закрытие сессии загрузите a с lazy b и попробуйте a1.getB (). equals (b1) дает false но если я сравню с a1.getB (). getId (). equals (b1.getId ()), тогда получится действительно странно !! я думаю, что это из-за объекта прокси Java Assist, в любом случае, чтобы решить эту проблему?

Ответы на вопрос(4)

Решение Вопроса

a.b ассоциация, Hibernate устанавливаетb поле вa на прокси. Прокси-сервер является экземпляром класса, который расширяет B, но не является B. Таким образом, ваш метод equals () всегда будет терпеть неудачу при сравнении экземпляра B без посредника с экземпляром B прокси, поскольку он сравнивает классы обоих объектов:

if (getClass() != obj.getClass())
    return false;

В случае Hibernate сущностей, вы должны заменить это на

if (!(obj instanceof B)) {
    return false;
}

Также обратите внимание, что

Hibernate recommends not implementing equals() and hashCode() by using the ID, but rather by using a natural identifier. Implementing it with IDs can cause problems because entities don't have an ID until they're saved and the ID is generated When using entity inheritance, the problem is even worse. Suppose B is a superclass of two sub-entities B1 and B2. Hiberante can't know which type (B1 or B2) is a.b before loading it. So a.b will be initialized to a proxy which is a subclass of B, but is not a subclass of B1 or B2. So the hashCode() and equals() methods should be implemented in B, but not be overridden in B1 and B2. Two B instances should be considered equal if they're instances of B, and have the same identifier.
 Jigar Parekh03 июл. 2012 г., 15:48
Спасибо, получил его. согласен с вами по вопросам, которые могут возникнуть из-за equals () и hashcode (), основанных на Id. я думаю, что сейчас я пойду с параметром instanceof, так как введение естественного идентификатора на этом этапе в приложении будет затруднительным.

Hibernate.getClass  за много лет я и не заметил проблемы

@Override    
public boolean equals(final Object obj) {
    if (this == obj) {
        return true;
    }
    if (obj == null) {
        return false;
    }
    if (Hibernate.getClass(this) != Hibernate.getClass(obj)) {
        return false;
    }

    ... check for values

    return true;
}
 01 сент. 2016 г., 11:09
За исключением того, что ваши доменные классы сейчас почти не связаны с Hibernate. Предположим, что вы хотите поделиться своим доменом с каким-либо другим приложением, вообще не использующим спящий режим ... теперь у вас проблемы. Не поймите меня неправильно, это сработает, но пахнет очень плохо. Также, если ребята из hibernate решат переместить \ удалить прокси-сервер, и вы обновите домен hibernate - он больше не будет компилироваться.

a1.getB().equals(b1) использованияObject.equals() (за исключением случаев, когда вы переопределяете equals () в вашем классе), который возвращает значение true, только если a1.getB () и b1 являются одним и тем же экземпляром. Я не знаю, что именно вы сделали (форматирование кода нарушено), но похоже, что вы загрузилиa снова в другой сессии, так что вы получите новый экземпляр дляa а такжеa.getB(), и следовательноObject.equals() возвращает ложь

a1.getB().getId().equals(b1.getId()) использованияLong.equals(), который возвращает true, если длинные значения одинаковы (даже для разных экземпляров объекта Long), и эти значения, очевидно, одинаковы.

 Jigar Parekh19 июн. 2012 г., 06:38
исправлено форматирование кода, согласно моему коду, я думаю, что он должен вызывать на равныхBaseEntity скорее, чемObject.equals()В настоящее время она вызываетObject.equals() не уверен почему
 Jigar Parekh02 июл. 2012 г., 21:00
обновленный код с точным равенством и хэш-кодом.
 29 июн. 2012 г., 16:48
Проблема в том, что позднее связывание Java не находит equals () в BaseEntity. Поэтому не могли бы вы предоставить полный код BaseEntity.equals (), включая точный параметр и модификатор доступа (public?).
 19 июн. 2012 г., 10:56
Можете ли вы добавить код для A.getB () (какого типа?), BaseEntity.equals () и для отображения A (хотя бы id и члена b)? Возможно, тогда я смогу увидеть больше.
 Jigar Parekh29 июн. 2012 г., 14:40
обновлен код для метода получения.

чтобы это работало, полезно, если вы не знаете, какой экземпляр B (может случиться, если вашequals в суперклассе)

if (HibernateProxyHelper.getClassWithoutInitializingProxy(this) != HibernateProxyHelper.getClassWithoutInitializingProxy(obj)) 
    return false
 01 сент. 2016 г., 11:10
Пожалуйста, смотрите мой комментарий к ответу Ральфа. Вы также связываете свои доменные классы с зависимостью Hibernate.

Ваш ответ на вопрос