Критерии .DISTINCT_ROOT_ENTITY не предотвращают дублирование объектов
У меня есть следующий метод dao:
@Override
public List<AdminRole> findAll() {
Session session = sessionFactory.getCurrentSession();
Criteria criteria = session.createCriteria(AdminRole.class);
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
return criteria.list();
}
На самом деле я хочу получить все записи из базы данных.
Иногда я вижу дубликаты. Это происходит, когда я добавляю пользователя с AdminRole.
Я читал, что это возможно, когда я использую EAGER
тип выборки, и это должно быть исправление, добавляющее следующую строку:
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
Но это мне не помогает.
my mapping:
@Entity
@Table(name = "terminal_admin_role")
public class AdminRole {
@Id
@Column(name = "role_id", nullable = false, unique = true)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_id")
@SequenceGenerator(name = "user_id", sequenceName = "user_id")
private Long adminId;
@Column(name = "role")
private String role;
public AdminRole(String role) {
this.role = role;
}
public AdminRole() {
}
// get set
@Override
public String toString(){
return role;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof AdminRole)) {
return false;
}
AdminRole adminRole = (AdminRole) o;
if (!role.equals(adminRole.role)) {
return false;
}
return true;
}
@Override
public int hashCode() {
return role.hashCode();
}
}
и
@Entity
@Table(name = "terminal_admin")
public class TerminalAdmin {
@ManyToMany(fetch=FetchType.EAGER,cascade=CascadeType.ALL)
@JoinTable(name = "admin_role", joinColumns = {
@JoinColumn(name = "admin_id", nullable = false) },
inverseJoinColumns = { @JoinColumn(name = "role_id",
nullable = false) })
private Set<AdminRole> adminRoles;
//...
}
P.S.
Я не могу переключить тип выборки.
Я не хочу, чтобы этот список был установлен.
Ответы
Ответ 1
Нет причин использовать DISTINCT_ROOT_ENTITY
или что-то подобное, все, что вам нужно:
session.createCriteria(AdminRole.class).list();
Если вы получаете дубликаты, то вы действительно имеете их в базе данных. Проверьте код, который сохраняет AdminRole
либо напрямую, либо путем каскадирования из других объектов.
При каскадировании PERSIST
/MERGE
операций с другими объектами убедитесь, что операция каскадирована на постоянный/отсоединенный экземпляр AdminRole
, а не на переходный (новый).
Ответ 2
Мои деньги на messing с hashCode/equals переопределениями и проксими Hibernate.
Из EqualsandHashCode
Однако, как только вы закрываете сеанс Hibernate, все ставки отключены. [...] Следовательно, если вы сохраняете коллекции объектов между сеансами, вы начнете испытывать нечетное поведение (в основном дублировать объекты в коллекциях).
Сначала я использовал бы org.apache.commons.lang3
так (это, очевидно, слишком дорого для сущностей Hibernate, но работает нормально с ними, и если он работает, это должно подтвердить мою догадку):
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
@Override
public boolean equals(Object other) {
return EqualsBuilder.reflectionEquals(this, other);
}
Если это сработает, вы можете пойти с менее дорогостоящим подходом:
@Override
public int hashCode() {
HashCodeBuilder hcb = new HashCodeBuilder();
hcb.append(role);
return hcb.toHashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof AdminRole)) {
return false;
}
AdminRole that = (AdminRole) obj;
EqualsBuilder eb = new EqualsBuilder();
eb.append(role, that.role);
return eb.isEquals();
}