JPA级联删除父级和子级

时间:2013-05-24 08:46:02

标签: jpa-2.0 ejb-3.0 parent-child cascading-deletes

我正在尝试学习和理解JPA,并且有一些关于一次性删除父母及其子女的问题。我正在使用OpenJPA和EJB3。我有两个实体,分类和产品。类别包含许多产品,产品具有对其父类别的引用。该类别的产品列表设置为级联。

//Category

    @Entity @NamedQueries({@NamedQuery(name = "Category.getCategoryByName", query = "SELECT c FROM Category c WHERE c.name = :name"),@NamedQuery(name = "Category.getCategoryByCategoryId", query = "SELECT c FROM Category c WHERE c.categoryid = :categoryid"), @NamedQuery(name = "Category.getAllCategories", query = "SELECT c FROM Category c left join fetch c.products")}) 

    public class Category implements Serializable {     
        private static final long serialVersionUID = 1L;

        @Id     
        @GeneratedValue(strategy=IDENTITY)  
        private Integer categoryid;         
        private String name;

        //bi-directional many-to-one association to Product     
        @OneToMany(cascade={CascadeType.ALL}, orphanRemoval = true, 
                   fetch = EAGER, mappedBy="category")  
        private List<Product> products;

    }

//Product

    @Entity
    @NamedQueries({@NamedQuery(name = "Product.getProductsByCategory", 
    query = "SELECT p.code, p.description, p.name, p.productid, p.weight FROM Product p    WHERE p.category.categoryid = :category_categoryid"),
    @NamedQuery(name = "Product.getProductByName", query = "SELECT p FROM Product p WHERE p.name = :name"),
    @NamedQuery(name = "Product.getProductByCode", query = "SELECT p FROM Product p WHERE p.code = :code"),
    @NamedQuery(name = "Product.getProductByProductId", query = "SELECT p FROM Product p WHERE p.productid = :productid"),
    @NamedQuery(name = "Product.getAllProducts", query = "SELECT p FROM Product p")})
     public class Product implements Serializable {
          private static final long serialVersionUID = 1L;

      @Id
      @GeneratedValue(strategy=IDENTITY)
      private Integer productid;
      private String code;
      private String description;
      private String name;
      private Double weight;

      //bi-directional many-to-one association to Category
      @ManyToOne(optional = false)
      @JoinColumn(name="CATEGORYID")
      private Category category;
    }
}

    // The EJB 

        @Stateless
        @LocalBean
        public class ShopManagerBean implements Serializable {
        @PersistenceContext(unitName = "TestEJBProject2", type =  PersistenceContextType.TRANSACTION)
        private EntityManager entityManager;



        @TransactionAttribute(TransactionAttributeType.REQUIRED)
        public void deleteCategory(Category category)
                throws TestApplicationException {

            try {
                Category actualCat = entityManager.find(Category.class,
                        category.getCategoryid());
                List<Product> products = actualCat.getProducts();
                if (products != null) {
                    Iterator<Product> it = products.iterator();
                    while (it.hasNext()) {
                        Product p = it.next();
                        it.remove();
                        entityManager.remove(p);
                    }
                }

                entityManager.refresh(actualCat);
                entityManager.remove(actualCat);

            } catch (Exception e) {
                e.printStackTrace();
                throw new TestApplicationException("Error creating new Product", e);
            }
        }
    }

如果我在deleteCategory方法中使用以下代码EJB,那么我无法删除父和子,因为我得到一个乐观锁定异常(在将对象实例“entity.Product-101”刷新到时检测到乐观锁定违规数据存储。这表明该对象在另一个事务中同时被修改。) - 抱怨将产品子项刷新到数据存储

 Category actualCat = entityManager.find(Category.class, category.getCategoryid());

  if (products != null) {
       actualCat.getProducts().clear();
   }
   entityManager.remove(actualCat);

但是,如果我在deleteCategory方法中使用以下代码,那么我可以删除父和子...但只有在我删除子项之后和删除父项之前调用entityManager.refresh(actualCat)(否则我得到一个乐观的锁定异常)。 有人可以向我解释为什么会出现这种情况,以及使用OpenJPA V2进行级联删除的正确/最佳方式是什么?

Category actualCat = entityManager.find(Category.class, category.getCategoryid());
List<Product> products = actualCat.getProducts();
if (products != null) {
    Iterator<Product> it = products.iterator();
    while (it.hasNext()) {
        Product p = it.next();
        it.remove();
        entityManager.remove(p);
    }
}
entityManager.refresh(actualCat);
entityManager.remove(actualCat);

提前感谢您的帮助

FAIS


加成

这是数据库创建脚本:

-

CREATE SCHEMA“DB2ADMIN”;

CREATE TABLE“DB2ADMIN”。“CATEGORY”(         “CATEGORYID”INTEGER NOT NULL NULL始终作为身份(从1 MINVALUE 1 MAXVALUE 2147483647 NO CYCLE CACHE 20开始增加1),         “NAME”VARCHAR(50)NOT NULL     )     DATA CAPTURE NONE;

CREATE TABLE“DB2ADMIN”。“PRODUCT”(         “PRODUCTID”INTEGER NOT NOT NULLERENT始终作为身份(从1 MINVALUE 1 MAXVALUE开始增加1 2147483647 NO CYCLE CACHE 20),         “CODE”CHAR(15)NOT NULL,         “NAME”VARCHAR(50)NOT NULL,         “DESCRIPTION”VARCHAR(200)NOT NULL,         “重量”浮动(53)非空,         “CATEGORYID”INTEGER NOT NULL     )     DATA CAPTURE NONE;

ALTER TABLE“DB2ADMIN”。“CATEGORY”添加约束“CATEGORY_PK”主键     ( “CATEGORYID”);

ALTER TABLE“DB2ADMIN”。“PRODUCT”添加约束“PRODUCT_PK”主键     ( “PRODUCTID”);

ALTER TABLE“DB2ADMIN”。“PRODUCT”ADD CONSTRAINT“PRODUCT_CATEGORY_FK”FOREIGN KEY     ( “CATEGORYID”)     参考“DB2ADMIN”。“CATEGORY”     ( “CATEGORYID”)     ON DELETE CASCADE;

0 个答案:

没有答案