1 Reply Latest reply on Oct 26, 2009 4:35 PM by ambrish_kumar

    Persisting Entity having Composite Id.

    ambrish_kumar

      Hi Everyone,


      I am facing a problem in which when I try to persist an Entity which has Composite key then it throws foreign key violation error. I am using Oracle 10g Express edition and SEAM 2.0.


      Here's the sample code:


      ProductMaster Table:



      CREATE TABLE  "PRODUCTMASTER" 
         (     "PRODUCTID" NUMBER NOT NULL ENABLE, 
           "PRODUCTNAME" VARCHAR2(400),     
            CONSTRAINT "PRODUCTMASTER_PK" PRIMARY KEY ("PRODUCTID") ENABLE      
         )
      
      
      CREATE OR REPLACE TRIGGER  "BI_PRODUCTMASTER" 
        before insert on "PRODUCTMASTER"               
        for each row  
      begin   
          select "PRODUCTMASTER_SEQ".nextval into :NEW.PRODUCTID from dual; 
      end;



      and Sequence for ProductMaster table is




      CREATE SEQUENCE   "PRODUCTMASTER_SEQ"  MINVALUE 1 MAXVALUE 999999999999999999999999999 INCREMENT BY 1 START WITH 61 CACHE 20 NOORDER  NOCYCLE 




      ProductMaster Entity :




      @Entity
      @Table(name = "PRODUCTMASTER", schema = "ROOT")
      @Name("productMaster")
      @SequenceGenerator(name="SEQ_PRODUCTMASTER",sequenceName="PRODUCTMASTER_SEQ")
      public class ProductMaster implements java.io.Serializable {
      
           // Fields getter setter
      
              @Id
           @Column(name = "PRODUCTID", unique = true, nullable = false)
           @NotNull     
           @GeneratedValue(strategy=GenerationType.SEQUENCE,generator="SEQ_PRODUCTMASTER")
           public int getProductId() {
                return productId;
           }
      
           public void setProductId(int productId) {
                this.productId = productId;
           }
      
      




      Category Table :




      CREATE TABLE  "CATEGORY" 
         (     "CATEGORYID" NUMBER NOT NULL ENABLE, 
           "CATEGORYNAME" VARCHAR2(400), 
            CONSTRAINT "CATEGORY_PK" PRIMARY KEY ("CATEGORYID") ENABLE
         )
      
      
      CREATE OR REPLACE TRIGGER  "BI_CATEGORY" 
        before insert on "CATEGORY"               
        for each row  
      begin   
          select "CATEGORY_SEQ".nextval into :NEW.CATEGORYID from dual; 
      end;




      and Sequence for Category Table is




      CREATE SEQUENCE   "CATEGORY_SEQ"  MINVALUE 1 MAXVALUE 999999999999999999999999999 INCREMENT BY 1 START WITH 41 CACHE 20 NOORDER  NOCYCLE




      Category Entity :




             @Id
           @Column(name = "CATEGORYID", unique = true, nullable = false)
           @NotNull
           @GeneratedValue(strategy=GenerationType.SEQUENCE,generator="SEQ_CATEGORY")
           public int getCategoryId() {
                return this.categoryId;
           }
      
           public void setCategoryId(int categoryId) {
                this.categoryId = categoryId;
           }
      





      And finally the ProductCategory table :




      CREATE TABLE  "PRODUCTCATEGORY" 
         (     "PRODUCTID" NUMBER NOT NULL ENABLE, 
           "CATEGORYID" NUMBER NOT NULL ENABLE, 
            CONSTRAINT "PRODUCTCATEGORY_PK" PRIMARY KEY ("PRODUCTID", "CATEGORYID") ENABLE, 
            CONSTRAINT "PRODUCTCATEGORY_FK" FOREIGN KEY ("PRODUCTID")
             REFERENCES  "PRODUCTMASTER" ("PRODUCTID") ENABLE, 
            CONSTRAINT "PRODUCTCATEGORY_FK2" FOREIGN KEY ("CATEGORYID")
             REFERENCES  "CATEGORY" ("CATEGORYID") ENABLE
         )
      



      ProductCategory Entity :




      @Entity
      @Table(name = "PRODUCTCATEGORY", schema = "ROOT")
      @Name("productCategory")
      public class ProductCategory implements java.io.Serializable {
      
           // Fields
      
           /**
            * 
            */
           private static final long serialVersionUID = 1L;
           private ProductCategoryId id;
           private Category category;
           private ProductMaster productMaster;
      
           // Constructors
      
           /** default constructor */
           public ProductCategory() {
           }
      
           /** full constructor */
           public ProductCategory(ProductCategoryId id, Category category,
                     ProductMaster productMaster) {
                this.id = id;
                this.category = category;
                this.productMaster = productMaster;
           }
      
           // Property accessors
           @EmbeddedId
           @AttributeOverrides( {
                     @AttributeOverride(name = "productId", column = @Column(name = "PRODUCTID", nullable = false)),
                     @AttributeOverride(name = "categoryId", column = @Column(name = "CATEGORYID", nullable = false)) })
           @NotNull
           public ProductCategoryId getId() {
                return this.id;
           }
      
           public void setId(ProductCategoryId id) {
                this.id = id;
           }
      
           @ManyToOne(fetch = FetchType.LAZY)
           @JoinColumn(name = "CATEGORYID", nullable = false, insertable = false, updatable = false)
           public Category getCategory() {
                return this.category;
           }
      
           public void setCategory(Category category) {
                this.category = category;
           }
      
           @ManyToOne(fetch = FetchType.LAZY)
           @JoinColumn(name = "PRODUCTID", nullable = false, insertable = false, updatable = false)
           public ProductMaster getProductMaster() {
                return this.productMaster;
           }
      
           public void setProductMaster(ProductMaster productMaster) {
                this.productMaster = productMaster;
           }



      Now, my requirement is that when I persist a Product then two entries should go into ProductCategory table for this Product and two different Categories (selected from list box) associated with Product.


      Here's my save() method:




      public void save() {
                
                getEntityManager().persist(getInstance());     
                
                if(selectedCategory != null){
                     
                     for(Category selCateg : selectedCategory){     
                               
                               ProductCategory newProdCat = new ProductCategory();
                               newProdCat.setId(new ProductCategoryId(getInstance().getProductId(),selCateg.getCategoryId()));
                               ProductMaster prodMast = getEntityManager().find(ProductMaster.class, getInstance().getProductId());
                               if(prodMast != null){
                               newProdCat.setProductMaster(prodMast);
                               newProdCat.setCategory(selCateg);
                               getEntityManager().persist(newProdCat);                         
                               }
                     }
                }          
           }



      Flush mode is Automatic. Even the Identity is not incrementing by 1.


      getInstance() representing the current ProductMaster entity's instance.


      Here's the error:


      integrity constraint (ROOT.PRODUCTCATEGORY_FK) violated - parent key not found



      Thanks & Regards


      Ambrish




        • 1. Re: Persisting Entity having Composite Id.
          ambrish_kumar

          Hi Everyone,


          My problem is solved by replacing trigger on ProductMaster table :




          CREATE OR REPLACE TRIGGER  "PRODUCTMASTER_T1" 
          BEFORE
          insert on "PRODUCTMASTER"
          for each row
          begin
          IF :NEW.PRODUCTID IS NULL THEN
                SELECT PRODUCTMASTER_SEQ.NEXTVAL INTO :NEW.PRODUCTID FROM DUAL;
              END IF; 
          
          end;






          Regards


          Ambrish