21

I have following hibernate entites:

@Entity
@Table(name = "model_view")
public class ModelView {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "modelView_id")
    private Integer id;

    @ManyToOne
    @NotNull
    @JoinColumn(name = "page_id", nullable = false, insertable = true, updatable = true)
    private Page page;

    /* getters and setters */
}

And:

@Entity
public class Page {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "page_id")
    private Integer id;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinColumn(name = "page_id")
    @IndexColumn(name = "modelView_id")
    private Set<ModelView> modelViews = new HashSet<ModelView>();

    /* getters and setters */
}

When I delete entity «ModelView» in DAO I have exception:

ORA-01407: unable to replace ("MODEL_VIEW"."PAGE_ID") to NULL

What is wrong? Why hibernate set foreign key to NULL before delete?

AnEi
  • 335
  • 1
  • 2
  • 9

1 Answers1

38

Why hibernate set foreign key to NULL before delete?

Hibernate tries to dereference the record you are attempting to delete by NULLing out the FK. Unfortunately, in most cases FKs are NOT NULLable. You have to tell Hibernate not to update the ModelView instances when deleting Page records.

Try changing insertable and updatable to false on the @JoinColumn mapping of page in ModelView:

@JoinColumn(name = "page_id", nullable = false, insertable = false, updatable = false)

When using these values, the ModelView records will remain. Again, this won't work if you enforce referential integrity. To get around this, you need to turn on cascading of deletes. I notice that in your code you already are using CascadeType.ALL which should work just fine.

Here is a SO Q&A which explains these fields:

In JPA why and how to use insertable and updatable parameter?

I had a similar problem which was fixed by using false for these values.

How can I map "insert='false' update='false'" on a composite-id key-property which is also used in a one-to-many FK?

Community
  • 1
  • 1
Jesse Webb
  • 43,135
  • 27
  • 106
  • 143
  • 1
    This is not solution for me, because in this case I have same error on insert entity «ModelView» (ORA-01400: unable to insert NULL to ("MODEL_VIEW"."PAGE_ID")). I try set FK nullable, but is not good idea. Is there any other solutions? – AnEi Jun 12 '13 at 11:48
  • 1
    This suggested solution _should_ solve that problem with INSERT statements too. When you set `insertable` and `updatable` to `false`, you are telling Hibernate that you will handle saving modifications to `ModelView` records manually. This means that you needs to INSERT/UPDATE `Page` records first, then set the FK on `ModelView`, then save those independently, preferably all in 1 transaction. If you do this, you should never have a case where the FK is NULL. – Jesse Webb Jun 12 '13 at 14:53
  • @AnEi If you are still having these errors, can you share some of the code you are using to cause it? – Jesse Webb Jun 12 '13 at 14:53
  • Adding "insertable = false, updatable = false" to @JoinColumn specification did the trick in my case. Thanks! Hibernate issues then only deletes in right order, doesn't attempt to update FK to null. – dorsz Apr 17 '16 at 09:17
  • Excuse me, but how do you "set the FK on ModelView" if ModelView.page is declared with updatable=false? According to docs, JPA provider will simply not generate update for that column when saving changes, isn't that true? So even if we do separate statement "x.page=null" that will not help. Granted, that will not be required if the field is not nullable; but what if I want to point that field to something other than it is now? No update will happen. So it's bad solution. And I may be reluctant to cascade removal either. And I'm left with no solution at all :) – Maksim Gumerov Jun 15 '18 at 10:33
  • 2
    @MaksimGumerov You should not set `updatable = false` on the `ModelView.page`, you should set it on the `Page.modelViews`. It is still possible to update your ModelView.page_id field in the DB by setting ModelView.page in code, it just won't be possible to update the FK using the Page.modelViews in code. If you are still confused, please ask a new question and you will get more help that way. Feel free to link to the new question here and I will take a look. – Jesse Webb Jun 15 '18 at 14:37
  • But, shouldn't Page.modelViews be the inverse side of relationship? Well, one of the sides should be, though in this code example both sides are owning. And no \@JoinColumn is allowed on inverse side ("Associations marked as mappedBy must not define database mappings like \@JoinTable or \@JoinColumn"). – Maksim Gumerov Jun 16 '18 at 03:07