我在数据库中有 2 个表:
- ads - 代表用户定义的广告
- ad_categories - 表示广告的类别
每个广告必须完全属于一个类别,因此在 ads 表中我定义了一个指向 ad_categories 的外键,其中 ON UPDATE NO ACTION ON DELETE NO ACTION。
在我的应用程序中,用户必须能够删除任何类别,但如果该类别包含广告,则必须在删除类别之前将它们移动到另一个类别。
em.getTransaction().begin();
// get currentNode
AdCategories currentNode = em.find(AdCategories.class, currentNodeId);
// get ads
List<Ads> resultList = em.createQuery("SELECT a from Ads a WHERE a.adCategoryId = :categoryId").setParameter("categoryId", currentNode).getResultList();
// get their new location
AdCategories newLocation = em.find(AdCategories.class, newLocationId);
// set their new location
for(Ads a: resultList)
a.setAdCategoryId(newLocation);
em.remove(currentNode);
em.getTransaction().commit();
我预计,受影响的广告将更改 ad_category_id,然后将删除空类别。但受影响的广告也被删除了!!
我在 EclipseLink 中启用了 FINEST 级别的日志记录,发现当事务提交时,首先将 UPDATE 查询发送到数据库,这会更改受影响广告的 ad_category_id,然后删除类别,但删除是级联广告!我不明白为什么,因为广告应该在删除之前更新 ad_category_ids 。
我知道,一种简单的解决方法是在删除类别之前调用em.flush()
,但我认为这不是最佳解决方案。我想,我需要了解这种行为。
我将 EclipseLink 与 NetBeans 和 PostgreSQL 一起使用。
表定义:
广告类别
@Entity
@Table(name = "ad_categories")
@XmlRootElement
@NamedQueries({
@NamedQuery(name = "AdCategories.findAll", query = "SELECT a FROM AdCategories a"),
@NamedQuery(name = "AdCategories.findById", query = "SELECT a FROM AdCategories a WHERE a.id = :id"),
@NamedQuery(name = "AdCategories.findByParentId", query = "SELECT a FROM AdCategories a WHERE a.parentId = :parentId"),
@NamedQuery(name = "AdCategories.findByCategoryOrder", query = "SELECT a FROM AdCategories a WHERE a.categoryOrder = :categoryOrder"),
@NamedQuery(name = "AdCategories.findByCategoryDepth", query = "SELECT a FROM AdCategories a WHERE a.categoryDepth = :categoryDepth"),
@NamedQuery(name = "AdCategories.findByName", query = "SELECT a FROM AdCategories a WHERE a.name = :name"),
@NamedQuery(name = "AdCategories.findByGrandParentId", query = "SELECT a FROM AdCategories a WHERE a.grandParentId = :grandParentId"),
@NamedQuery(name = "AdCategories.findByParentName", query = "SELECT a FROM AdCategories a WHERE a.parentName = :parentName"),
@NamedQuery(name = "AdCategories.findByGrandParentName", query = "SELECT a FROM AdCategories a WHERE a.grandParentName = :grandParentName")})
public class AdCategories implements Serializable {
@OneToMany(cascade = CascadeType.ALL, mappedBy = "adCategoryId")
private Collection<Ads> adsCollection;
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "id")
private Integer id;
@Basic(optional = false)
@Column(name = "parent_id")
private int parentId;
@Basic(optional = false)
@Column(name = "category_order")
private short categoryOrder;
@Basic(optional = false)
@Column(name = "category_depth")
private short categoryDepth;
@Basic(optional = false)
@Column(name = "name")
private String name;
@Column(name = "grand_parent_id")
private Integer grandParentId;
@Column(name = "parent_name")
private String parentName;
@Column(name = "grand_parent_name")
private String grandParentName;
...
广告
@Entity
@Table(name = "ads")
@XmlRootElement
@NamedQueries({
@NamedQuery(name = "Ads.findAll", query = "SELECT a FROM Ads a"),
@NamedQuery(name = "Ads.findByAdId", query = "SELECT a FROM Ads a WHERE a.adId = :adId"),
@NamedQuery(name = "Ads.findByName", query = "SELECT a FROM Ads a WHERE a.name = :name"),
@NamedQuery(name = "Ads.findByDescriptionShort", query = "SELECT a FROM Ads a WHERE a.descriptionShort = :descriptionShort"),
@NamedQuery(name = "Ads.findByDescriptionLong", query = "SELECT a FROM Ads a WHERE a.descriptionLong = :descriptionLong")})
public class Ads implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "ad_id")
private Integer adId;
@Basic(optional = false)
@Column(name = "name")
private String name;
@Basic(optional = false)
@Column(name = "description_short")
private String descriptionShort;
@Basic(optional = false)
@Column(name = "description_long")
private String descriptionLong;
@JoinColumn(name = "ad_category_id", referencedColumnName = "id")
@ManyToOne(optional = false)
private AdCategories adCategoryId;
...