简体   繁体   中英

Getting Hibernate to cascade on save, but not delete?

So I'm having a problem with my hibernate implementation. When I try to delete a parent class, I receive a foreign key constraint exception on a class deep within the cascade hierarchy. Before I go into specifics, I'll first describe the relationships of the classes, as it has a bearing on how they need to be saved and deleted.

At the top level, I have a Customer class, which contains a list of DefaultMask objects. This is the master list, in that these default masks are used by other classes in my object hierarchy, but always from this list. Masks are only created into this list and deleted from this list.

Further down the hierarchy, I have a Column class, which can (optionally) have a DefaultMask set on it. To describe the relationship more succinctly;

A Customer OWNS zero to many DefaultMasks. A Customer OWNS zero to many Columns. A Column may have one DefaultMask.

In my application, when I attempt to delete a Customer, the exception comes from the foreign-key constraint on the Column class to the DefaultMask class, and I believe the problem is incorrect settings with CascadeType. I have researched the problem and found information on an attribute called mappedBy and on using Hibernate's own CascadeType.SAVE_UPDATE (in order to prevent Hibernate trying to delete a DefaultMask held by a Column), but I will admit I am a bit lost here and could use some direct guidance. Relevant code for the classes and the actual exception message are below.

Customer:

@Entity
public class Customer {

@Id
private String id;
@OneToMany(cascade = CascadeType.ALL)
private List<DefaultMask> masks;
    //(Columns are held further down in hierarchy)

Column:

@Entity
@Table(name = "WarehouseColumn")
public class Column implements Comparable<Column> {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int hibernateID;
@OneToOne
private DefaultMask mask;

DefaultMask:

@Entity
public class DefaultMask implements Mask {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int hibernateID;
private String type;
private String mask;

Exception message:

org.hibernate.exception.ConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails ( hibernate . WarehouseColumn , CONSTRAINT FK8BB153D994AD57D3 FOREIGN KEY ( mask_hibernateID ) REFERENCES DefaultMask ( hibernateID )) Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails ( hibernate . WarehouseColumn , CONSTRAINT FK8BB153D994AD57D3 FOREIGN KEY ( mask_hibernateID ) REFERENCES DefaultMask ( hibernateID ))

Cascading is closely related to the concept of logical ownership.

Basically, you need to choose one of the following options:

  • Customer logically owns its DefaultMask s. In this case you want DefaultMask s to be deleted when you delete a Customer , therefore you need to use CascadeType.ALL . Since Column references DefaultMask , it's probably owned by Customer as well, and should be deleted to

    It can be achieved by using bidirectional relationship between DefaultMask and Column with appropriate cascading, as follows:

     @Entity public class DefaultMask implements Mask { @OneToOne(mappedBy = "mask", cascade = CascadeType.ALL) Column column; ... } 
  • DefaultMask s are entities on its own, and Customer just references existing DefaultMask s. In this case you probably don't need to use cascading for this relationship at all.

You're rying to delete a customer, which automatically deletes its list of default masks. But one of these masks is referenced by a column. So the database (and thus Hibernate) refuses to execute the deletion, because it would leave the column in an inconsistent state: it would reference a default mask that doesn't exist anymore.

So you have several functional choices:

  • leave it as it is: the customer can't be deleted because one of its masks is still referenced by a column
  • remove the cascade: deleting the customer will delete the customer but not its masks.
  • find all the columns which reference any of the default masks of the user to be deleted, and remove these columns. Then, remove the user and its default masks
  • find all the columns which reference any of the default masks of the user to be deleted, and set their mask fild to null. Then, remove the user and its default masks

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM