Hibernate выдает «более одной строки с данным идентификатором» один раз, но не после этого - PullRequest
0 голосов
/ 08 мая 2019

У меня есть приложение с таблицей истории, сопоставленной с представлением отношения ManyToOne следующим образом

@Entity
@Table(name = "HISTORY_TABLE", schema = "MY_SCHEMA")
public class HAction implements Serializable {
...

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumns({    
    @JoinColumn(name = "ID_WHO", referencedColumnName = "ID_USER"),
    @JoinColumn(name = "CT_WHO", referencedColumnName = "CT_SEQUENCE")
    })
private VwUsers whoDidTheAction;

...

//Getters & Setters

}

При запуске приложения обнаружилось знаменитое «Обнаружено более одной строки с данным идентификатором».

Поэтому я пошел в отладку, чтобы выяснить, что за пользователь вызвал эту проблему. Действительно, в базе данных есть дубликат объекта View. Однако во время отладки я наткнулся на следующую «магию»

Не уверен, имеет ли это какое-либо отношение к моей IDE, но при использовании инспектора кода на intelliJ (отображение в Eclipse) и выдаче следующего

hAction.getWhoDidTheAction().getId();

Это дало мне ошибку, но при повторном выполнении, на том же экране "сеанс", ошибки не было, результат был там, как и ожидалось.

Кто-нибудь знает источник этого поведения? Я не мог найти ничего, связанного с этим.

полный класс HAction:

@Entity
@Table(name = "HISTORY_TABLE", schema = "MY_SCHEMA")
public class HAction implements Serializable {

 /**  */
 private static final long serialVersionUID = -294276241063426049 L;

 @Id
 @Column(name = "ID_HISTORY_TABLE")
 @SequenceGenerator(name = "SQ_HISTORY_TABLE", sequenceName = "MY_SCHEMA.SQ_HISTORY_TABLE", allocationSize = 1)
 @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SQ_HISTORY_TABLE")
 private Long idHAction;

 @ManyToOne(fetch = FetchType.LAZY)
 @JoinColumn(name = "ID_ACTION", referencedColumnName = "ID_ACTION")
 private SAction action;

 @Transient
 private Long idActionTransient;

 @Enumerated(EnumType.STRING)
 @Column(name = "CS_OPERATION")
 private OperationEnum csOperation;

 @Temporal(TemporalType.TIMESTAMP)
 @Column(name = "DT_OPEARATION")
 private Date dhOPeration;

 @ManyToOne(fetch = FetchType.LAZY)
 @JoinColumn(name = "ID_USER", referencedColumnName = "ID_USER")
 private VwUser user;

 @Column(name = "CD_PROTOCOL")
 private String cdProtocol;

 @Temporal(TemporalType.DATE)
 @Column(name = "DT_PROTOCOL")
 private Date dtProtocol;

 @Column(name = "DS_ACTION")
 private String dsAction;

 @Temporal(TemporalType.DATE)
 @Column(name = "DT_PREDICTION")
 private Date dtPrediction;

 @Enumerated(EnumType.STRING)
 @Column(name = "CS_ORIGIN")
 private OriginEnum csorigin;

 @ManyToOne(fetch = FetchType.LAZY)
 @JoinColumn(name = "ID_REQUIRED_BY_SECTOR", referencedColumnName = "ID_SECTOR")
 private VwSector vwSector;

 @ManyToOne(fetch = FetchType.LAZY)
 @JoinColumn(name = "ID_REQUIRED_BY_HQ", referencedColumnName = "ID_HQ")
 private VwHq vwHq;

 @ManyToOne(fetch = FetchType.LAZY)
 @JoinColumn(name = "ID_REQUIRED_BY_LOCAL", referencedColumnName = "ID_LOCAL")
 private VwLocal vwLocal;

 @ManyToOne(fetch = FetchType.LAZY)
 @JoinColumn(name = "ID_REQUIRED_BY_ASSOC", referencedColumnName = "ID_ASSOC")
 private VwAssoc vwAssoc;

 @ManyToOne(fetch = FetchType.LAZY)
 @JoinColumn(name = "ID_REQUIRED_BY_INTER", referencedColumnName = "ID_INTER")
 private VwInter vwInter;

 @Column(name = "DAY_VL")
 private Double dayValue;

 @Column(name = "MAT_VAL")
 private Double matValue;

 @Column(name = "OP_VALUE")
 private Double opValue;

 @Column(name = "TERC_VALUE")
 private Double tercValue;

 @Column(name = "TERC_SERV_VALUE")
 private Double tercServValue;

 @Column(name = "PUB_VALUE")
 private Double pubValue;

 @ManyToOne(fetch = FetchType.LAZY)
 @JoinColumn(name = "ID_RESPONSIBLE", referencedColumnName = "ID_UNIT")
 private Units unit;

 //This is the first fragment
 @ManyToOne(fetch = FetchType.LAZY)
 @JoinColumns({
  @JoinColumn(name = "ID_BOSS", referencedColumnName = "ID_USER"),
  @JoinColumn(name = "CT_BOSS", referencedColumnName = "CT_SEQUENCE")
 })
 private VwUsers whoDidTheActionBoss;
 //
 @ManyToOne(fetch = FetchType.LAZY)
 @JoinColumns({
  @JoinColumn(name = "ID_SUB_BOSS", referencedColumnName = "ID_USER"),
  @JoinColumn(name = "CT_SUB_BOSS", referencedColumnName = "CT_SEQUENCE")
 })
 private VwUsers whoDidTheActionSubBoss;

 @ManyToOne(fetch = FetchType.LAZY)
 @JoinColumn(name = "ID_PHONE", referencedColumnName = "ID_PHONE")
 private VwPhone vwPhone;

 @ManyToOne(fetch = FetchType.LAZY)
 @JoinColumn(name = "ID_EMAIL", referencedColumnName = "ID_EMAIL")
 private VwEmail vwEmail;

 @ManyToOne(fetch = FetchType.LAZY)
 @JoinColumn(name = "ID_EMAIL_SUB_BOSS", referencedColumnName = "ID_EMAIL")
 private VwEmail vwEmailSubBoss;

 @ManyToOne(fetch = FetchType.LAZY)
 @JoinColumn(name = "ID_PHONE_SUB_BOSS", referencedColumnName = "ID_PHONE")
 private vwPhone vwPhoneSubBoss;

 @Column(name = "PROTOCOL")
 private String protocol;

 @Enumerated(EnumType.STRING)
 @Column(name = "CONN")
 private VwConn conn;

 @ManyToOne(fetch = FetchType.LAZY)
 @JoinColumn(name = "ID_TYPE", referencedColumnName = "ID_TYPE")
 private SType type;

 @OneToMany(fetch = FetchType.LAZY, mappedBy = "id.HAction")
 private List < SFiles > files;

 @OneToMany(fetch = FetchType.LAZY, mappedBy = "id.HAction")
 private List < SThemes > themes;

 @Column(name = "ST_ARCHIVED")
 private Character archived;

 @Temporal(TemporalType.DATE)
 @Column(name = "DT_VIG")
 private Date dtVig;

 /**
  * Create Object {@link HAction}.
  * 
  */
 public HAction() {}

 //Getters & Setters
}

1 Ответ

0 голосов
/ 08 мая 2019

После некоторого более глубокого исследования с несколькими коллегами мне указали, что это может быть поведение реализации прокси, и это действительно так.

Во время выполнения «getId ()» прокси-класс проверяет, удовлетворено ли отношение «многие к одному», если нет, то заполняет результат данными первого найденного результата, ЧЕМ выдает исключение.Это особенно полезно для отладки, поскольку дает вам хотя бы один из дублированных объектов.Это предполагаемое поведение.

Поскольку у меня уже есть объект в памяти, нет необходимости повторно искать базу данных для записей, поэтому метод "getId ()" возвращает идентификатор объекта.первый элемент и не выдает исключение, поскольку он не запросил базу данных снова.

Некоторое объяснение поведения прокси можно найти здесь

Некоторая информация оЛенивый инициализатор можно найти здесь

Спасибо всем, кто нашел время, чтобы помочь мне.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...