简体   繁体   English

HIbernate无法使用外键删除实体。 外键设置为null

[英]HIbernate Can't delete Entity with foreign key. Foreign key gets set to null

This question has been asked in many forms here but none of the solutions seem to work for me. 这个问题在很多方面都有问题,但没有一个解决方案对我有用。 I'm trying to delete the parent entity and I want all of the child entities to also be deleted. 我正在尝试删除父实体,我希望也删除所有子实体。

My entities: 我的实体:

@Entity
@Table(name = "item", catalog = "myshchema")
public class Item implements java.io.Serializable {

@JoinColumn(name = "item_id", insertable = false, updatable = false, nullable = false)
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
private Set<ItemCategory> categories;

/* Getters and Setters and other fields*/
}

Table for Item: 项目表:

CREATE TABLE `item` (
`item_id` int(11) NOT NULL AUTO_INCREMENT,
`store_id` int(11) NOT NULL,
PRIMARY KEY (`item_id`),
UNIQUE KEY `item_id_UNIQUE` (`item_id`),
KEY `FK_ITEM_STORE_ID_idx` (`store_id`),
CONSTRAINT `FK_ITEM_STORE_ID` FOREIGN KEY (`store_id`) REFERENCES `store`   (`store_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=84 DEFAULT CHARSET=utf8;

And my other entity 而我的另一个实体

@Entity
@Table(name = "item_category", catalog = "myschema")
@IdClass(ItemCategoryIndex.class)
public class ItemCategory implements java.io.Serializable {

@Id
@Column(name = "category_id", unique = true, nullable = false, insertable = false, updatable = false)
private Integer categoryId;
@Id
private Store store;
@Id
private Item item;
@Id
private String categoryName;

/* Getters and Setters */
}

Table for ItemCategory: ItemCategory表:

CREATE TABLE `item_category` (
`category_id` int(11) NOT NULL AUTO_INCREMENT,
`store_id` int(11) NOT NULL,
`item_id` int(11) NOT NULL,
`category_name` varchar(45) NOT NULL,
PRIMARY KEY (`category_id`),
UNIQUE KEY `category_id_UNIQUE` (`category_id`),
UNIQUE KEY `IDX_UNIQUE_STORE_CATEGORY`     (`store_id`,`item_id`,`category_name`) USING BTREE,
KEY `FK_CATEGORY_STORE_ID_idx` (`store_id`),
KEY `FK_ITEM_CATEGORY_ID_idx` (`item_id`),
CONSTRAINT `FK_CATEGORY_STORE_ID` FOREIGN KEY (`store_id`) REFERENCES     `store` (`store_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `FK_ITEM_CATEGORY_ID` FOREIGN KEY (`item_id`) REFERENCES `item`     (`item_id`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=162 DEFAULT CHARSET=utf8;

I try to delete the item like this: 我尝试删除这样的项目:

Item item = entityManager.find(Item.class, idList.get(i));
entityManager.remove(item);

My logs show that Hibernate is trying to set the primary key for ItemCategory to null: 我的日志显示Hibernate正在尝试将ItemCategory的主键设置为null:

Hibernate: update myschema.item_category set item_id=null where item_id=?
ERROR o.h.e.jdbc.spi.SqlExceptionHelper.logExceptions 146 - Column 'item_id' cannot be null

I even tried looping through the child records and deleting them manually, but Hibernate still issues this update to null query. 我甚至尝试循环遍历子记录并手动删除它们,但Hibernate仍然将此更新发送到null查询。 What am I doing wrong? 我究竟做错了什么?

I have to break your problem down to two parts 我必须将你的问题分解为两部分

First - let's talk about your database schema design. 首先 - 让我们谈谈您的数据库架构设计。

According to your schema, item and item_category has a one-to-many relationship meaning an item can have/be-assigned-to different categories but different items cannot have/be-assigned-to the same category. 根据您的架构, itemitem_category具有一对多的关系,这意味着一个项目可以被分配/分配给不同的类别,但是不同的项目不能/被分配到同一个类别。

That is totally fine if it is indeed your business requirement , I mention it because it does not make sense to me and this circumstance rarely happens. 如果它确实是你的业务需求那就完全没问题,我提到它是因为它对我没有意义,这种情况很少发生。

If what you want is that a category can have multiple items and vice versa, item and item_category must be a many-to-many relationship. 如果你想要的是一个类别可以有多个项目,反之亦然, itemitem_category必须是多对多关系。 There should be a join table additionally. 此外应该有一个连接表

Second - let's say the schema don't change 第二 - 让我们说架构不会改变

ItemCategory is the owner of the relationship because it has a foreign key item_id refering to item table. ItemCategory是关系的所有者,因为它具有引用item表的外键item_id So the ItemCategoy should look roughly like this: 所以ItemCategoy看起来应该大致如下:

@Entity
@Table(name = "item_category")
public class ItemCategory {

@Id
private Integer categoryId;

private Store store;

@ManyToOne
@JoinColumn(name="item_id", /*cascade = ...*/)
private Item item;

private String categoryName;

/* Getters and Setters */
}

Your Item entity will be roughly like this: 您的Item实体大致如下:

@Entity
@Table(name = "item", catalog = "myshchema")
public class Item implements java.io.Serializable {

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true, mappedBy="item")
private Set<ItemCategory> categories; //`mappedBy`used here because this entity is not the owner of the relationship according to what mentioned above

/* Getters and Setters and other fields*/
}  

To remove all the child entities( ItemCategory ) from Item , simply 要简单地从Item删除所有子实体( ItemCategory

em.remove(item);

The orphanRemoval is true , deleting the parent, the children will be deleted as well. orphanRemovaltrue ,删除父级,子级也将被删除。

In Hibernate, you need to decide who is owning the relationship. 在Hibernate中,您需要决定谁拥有这种关系。 If you have the parent side (ItemCategory) owning the relationship, you will find insertion/deletion of Item+ ItemCategory will involve update of item_id in ItemCategory table (which is what I observed from your exception). 如果您拥有关系的父方(ItemCategory),您会发现Item + ItemCategory的插入/删除将涉及更新ItemCategory表中的item_id(这是我从您的异常中观察到的)。 In most case it is not preferable. 在大多数情况下,它不是优选的。 We usually let the children own the relationship. 我们通常让孩子们拥有这种关系。 This is done by using mappedBy 这是通过使用mappedBy完成的

(pseudo-code) (伪代码)

class Item {
  //...

  @OneToMany(mappedBy = "item", cascade=ALL, orphanRemoval=true)
  private Set<ItemCategory> categories;
}

class ItemCategory {
  //...

  @ManyToOne
  @JoinColumn(name="item_id")
  Item item;
}

The trick here is mappedBy 这里的技巧是mappedBy

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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