1

In our domain model, one Event is designed to have zero or one Notification, so I started to use @OneToOne annotation for entity relation:

class Event {
...
    @OneToOne(mappedBy = "event")
    Notification notification;

In most cases it works fine, but in very rare cases there are duplicate Notifications for a single Event, which differ only by milliseconds in timestamp. If such happens, Hibernate throws an exception:

javax.persistence.PersistenceException: org.hibernate.HibernateException: More than one row with the given identifier was found: 1290338, for class: Xxx

-- and the entire result set fails.

The workaround I implemented: annotate relation as @OneToMany but return a single Notification through a getter:

@OneToMany(mappedBy = "event")
List<Notification> notifications;
...

public Notification getNotification() {
    return notifications == null || notifications.isEmpty()
           ? null : notifications.get(0);
}

It works pretty fine, but the thing I dislike here is that bean style of class is broken. My question: is there Hibernate preference to suppress mentioned exception, so I can manage without custom getter?

Database is managed and populated by outer system, so there is no possibility to add constraint nor control insertion of duplicates.

Alex Salauyou
  • 14,185
  • 5
  • 45
  • 67
  • How do you handle calling setNotification, refreshing, and then having it return a different notification then you just set? If multiple notifications map to this Event, then it is a 1:M relationship. Your application may only care about the first notification in the list, but it might not always be so. – Chris Sep 02 '15 at 17:55
  • 1
    How to fix a "more than one" error on a OneToOne mapping: Fix the underlying data, because it's obviously *corrupt* if a one-to-one relationship has multiple relations. --- *Or* maybe the relation is not one-to-one and you need to understand the data better. – Andreas Sep 02 '15 at 18:04
  • @Andreas I completely understand that data are corrupted and relationship is not actually one-to-one (regardless of that by design and specification it should be). But I cannot influense, because database is managed by another independent system. – Alex Salauyou Sep 02 '15 at 18:17
  • @chris db is fully managed by outer system, we do not modify data. – Alex Salauyou Sep 02 '15 at 18:20
  • 2
    If data is not one-to-one, don't tell hibernate is it. Hibernate is doing the right thing, by letting you know that the data is corrupt, according to the information you told it. *You* have to decide which record you want when multiple records exist. Hibernate can't do that for you. Hibernate *can* give you all the records (one-to-many), and you must decide in your code which record to use. – Andreas Sep 02 '15 at 18:22
  • For being one to one, then underlaying DB should ensure the atomicity of the operations done. So you've got to choices: tell the outer system to modify the DB in order to guarantee the atomicity or take the relation as one to many (as it actually is). Hibernate has nothing to do with it. – Aritz Sep 02 '15 at 18:24
  • @XtremeBiker Andreas are you guys sure there is *definitely* no such Hibernate preference to handle such cases? – Alex Salauyou Sep 02 '15 at 18:30
  • @SashaSalauyou No, why should it exist? If you setup a *OneToOne* Constraint, there CAN'T be multiple results. You can't define *OneToOne* and expect Hibernate to handle cases if there are multiple results! This is not how it works! :-) – dognose Sep 02 '15 at 18:38
  • @dognose thank you, so I need to continue using the workaround. I had a piece of hope there is such advanced feature out of the box. – Alex Salauyou Sep 02 '15 at 18:43
  • @SashaSalauyou You get it wrong - To retrieve the first message out of a `OneToMany` Relation, using `collection.get(0)` is no workarround! The Absence of *handling wrong User-Definition* is NOT an absence of a *advanced feature* - You also can't define a date column and expect ANY software to be able to fetch that value as a boolean! Same goes for relations! Use a correct definition, then Hibernate is your best friend. Mess up, Hibernate will be your worst enemy! – dognose Sep 02 '15 at 19:30
  • 1
    Other providers just ignore multiple results and return the first one. The issue is that get(0) does not ensure you get the same notification instance each time. Ordering will help, but if that other system isn't using or populating your relationship as a 1:1 means it really isn't a 1:1. – Chris Sep 02 '15 at 19:34
  • @Chris thank you, I understand it clearly and from the beginning. Unfortunately, sometimes you need to deal with result of other developers' work – Alex Salauyou Sep 02 '15 at 20:31

0 Answers0