Yes, i test with EJB Beta and it seems that orphan still doesnot work. Here is the scenario
Category (1)-------------(M) Product
The infact even the adding new Product to the category also does not work untill i setProducts(products) again. This is weird as it was working find with preview 5. Here are the entity beans
Category
package com.kt.inventory.entity.bean;
import org.hibernate.annotations.*;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratorType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Id;
import javax.persistence.CascadeType;
import javax.persistence.FetchType;
import java.util.ArrayList;
import java.util.Collection;
/**
* Comment
*
* @author <a href="mailto:murtuza@murtuza.net">Murtuza Vohra</a>
* @version $Revision: 1.0 $
*/
@Entity
@Table(name = "category")
public class Category implements java.io.Serializable {
private long catNo;
private String catName;
private long parent;
private String description;
private String flex1;
private String flex2;
private String flex3;
private Collection<Product> products;
public Category() {
}
public Category(String name, long parent, String description, String flex1, String flex2, String flex3) {
super();
// TODO Auto-generated constructor stub
catName = name;
this.parent = parent;
this.description = description;
this.flex1 = flex1;
this.flex2 = flex2;
this.flex3 = flex3;
}
public Category(long no, String name, long parent) {
super();
// TODO Auto-generated constructor stub
catNo = no;
catName = name;
this.parent = parent;
}
@Id(generate = GeneratorType.AUTO)
public long getCatNo() {
return catNo;
}
public void setCatNo(long catNo) {
this.catNo = catNo;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getFlex1() {
return flex1;
}
public void setFlex1(String flex1) {
this.flex1 = flex1;
}
public String getFlex2() {
return flex2;
}
public void setFlex2(String flex2) {
this.flex2 = flex2;
}
public String getFlex3() {
return flex3;
}
public void setFlex3(String flex3) {
this.flex3 = flex3;
}
public String getCatName() {
return catName;
}
public void setCatName(String catName) {
this.catName = catName;
}
public long getParent() {
return parent;
}
public void setParent(long parent) {
this.parent = parent;
}
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "category")
@org.hibernate.annotations.Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
public Collection<Product> getProducts() {
return products;
}
public void setProducts(Collection<Product> products) {
this.products = products;
}
}
Product Entity
package com.kt.inventory.entity.bean;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratorType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Id;
import javax.persistence.CascadeType;
import javax.persistence.FetchType;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
/**
* Comment
*
* @author <a href="mailto:murtuza@murtuza.net">Murtuza Vohra</a>
* @version $Revision: 1.0 $
*/
@Entity
@Table(name = "product")
public class Product implements Serializable {
private String country;
private String dcountry;
private String description;
private String flex1;
private String flex2;
private String flex3;
private boolean isCancelled;
private String partNumber;
private String productName;
private long productNo;
private double reorderLevel;
private Category category;
public Product() {
super();
// TODO Auto-generated constructor stub
}
public Product(String name, String number, String country, String description, Category category) {
super();
// TODO Auto-generated constructor stub
this.country = country;
this.description = description;
partNumber = number;
productName = name;
this.category = category;
}
public Product(String name, String number, String country, String dcountry, String description, String flex1, String flex2, String flex3, boolean cancelled, double level, Category category) {
super();
// TODO Auto-generated constructor stub
this.country = country;
this.dcountry = dcountry;
this.description = description;
this.flex1 = flex1;
this.flex2 = flex2;
this.flex3 = flex3;
isCancelled = cancelled;
partNumber = number;
productName = name;
reorderLevel = level;
this.category = category;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getDcountry() {
return dcountry;
}
public void setDcountry(String dcountry) {
this.dcountry = dcountry;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getFlex1() {
return flex1;
}
public void setFlex1(String flex1) {
this.flex1 = flex1;
}
public String getFlex2() {
return flex2;
}
public void setFlex2(String flex2) {
this.flex2 = flex2;
}
public String getFlex3() {
return flex3;
}
public void setFlex3(String flex3) {
this.flex3 = flex3;
}
public boolean isCancelled() {
return isCancelled;
}
public void setCancelled(boolean isCancelled) {
this.isCancelled = isCancelled;
}
public String getPartNumber() {
return partNumber;
}
public void setPartNumber(String partNumber) {
this.partNumber = partNumber;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
@Id(generate = GeneratorType.AUTO)
public long getProductNo() {
return productNo;
}
public void setProductNo(long productNo) {
this.productNo = productNo;
}
public double getReorderLevel() {
return reorderLevel;
}
public void setReorderLevel(double reorderLevel) {
this.reorderLevel = reorderLevel;
}
@ManyToOne
@JoinColumn(name = "catNo")
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
}
The InventoryManager session bean
package com.kt.inventory.session.bean;
import java.util.*;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import com.kt.inventory.entity.bean.*;
@Stateless
@Remote(InventoryManager.class)
public class InventoryManagerBean implements InventoryManager{
private @PersistenceContext(unitName="ktmanager") EntityManager manager;
public Category findCategoryById(long id) throws Exception{
return manager.find(Category.class, new Long(id));
}
public Collection<Category> findSubCategory(long parent) throws Exception{
return manager.createQuery("from Category c where c.parent = :parent").setParameter("parent", parent).getResultList();
}
public Collection<Category> findCategoryByKeyword(String keywords) throws Exception{
return manager.createQuery("SELECT OBJECT(c) FROM Category AS c WHERE "+
"c.catName LIKE '%"+keywords+"%' OR " +
"c.description LIKE '%"+keywords+"%' OR " +
"c.flex1 LIKE '%"+keywords+"%' OR "+
"c.flex2 LIKE '%"+keywords+"%' OR "+
"c.flex3 LIKE '%"+keywords+"%'").getResultList();
}
public Product findProductById(long id) throws Exception{
return manager.find(Product.class, new Long(id));
}
public Collection<Product> findProductByCategory(long catNo) throws Exception{
return manager.find(Category.class, new Long(catNo)).getProducts();
}
public Collection<Product> findProductByKeyword(String keywords) throws Exception {
return manager.createQuery("SELECT OBJECT(p) FROM Product as p WHERE "+
"p.productName LIKE '%"+keywords+"%' OR " +
"p.description LIKE '%"+keywords+"%' OR " +
"p.country LIKE '%"+keywords+"%' OR " +
"p.dcountry LIKE '%"+keywords+"%' OR " +
"p.partNumber LIKE '%"+keywords+"%' OR " +
"p.flex1 LIKE '%"+keywords+"%' OR "+
"p.flex2 LIKE '%"+keywords+"%' OR "+
"p.flex3 LIKE '%"+keywords+"%'").getResultList();
}
//public void addCategory(long catno, String name, long parent, String description) throws Exception
public long addCategory(Category category) throws Exception
{
/*Category category = new Category();
category.setCatNo(catno);
category.setCatName(name);
category.setParent(parent);
category.setDescription(description);*/
if(category != null)
{
manager.persist(category);
//category = manager.find(Category.class, new Long(category.getCatNo()));
}
return category.getCatNo();
}
public void udpateCategory(Category category) throws Exception
{
if(category!=null)
{
System.out.println("Products: " + category.getProducts().size());
manager.merge(category);
manager.find(Category.class, new Long(category.getCatNo()));
}
}
}
and the test client
/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package com.kt.test.order;
import com.kt.order.entity.bean.*;
import com.kt.order.session.bean.*;
import com.kt.inventory.entity.bean.*;
import com.kt.inventory.session.bean.*;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.util.*;
/**
* Comment
*
* @author <a href="mailto:bill@jboss.org">Bill Burke</a>
* @version $Revision: 1.1.6.3 $
*/
public class TestClient
{
public static void main(String[] args)
{
try {
//String serverName = "localhost";
//Hashtable<String,String> ht = new Hashtable<String,String>();
//ht.put("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");
//ht.put("java.naming.factory.url.pkgs","org.jboss.naming:org.jnp.interfaces");
//ht.put("java.naming.provider.url",serverName);
SecurityManager security = System.getSecurityManager();
InitialContext ctx = new InitialContext();
//testAddCatAndSubCat(ctx);
//testAddProduct(ctx);
//testUpdateProduct(ctx);
testAddDeleteProduct(ctx);
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void testAddDeleteProduct(InitialContext ctx)
{
try {
InventoryManager im = (InventoryManager)ctx.lookup(InventoryManager.class.getName());
Collection<Category> list = im.findCategoryByKeyword("hinges");
if(list==null)
return;
Category cat = new LinkedList<Category>(list).get(0);
System.out.println("Found Category: " + cat.getCatName() + " catNo: " + cat.getCatNo());
LinkedList<Product> products = new LinkedList<Product>(cat.getProducts());
System.out.println("Found products: " + products.size());
Product prod = products.remove(0);
prod.setCategory(null);
System.out.println("Removed: " + prod.getProductName() + " " + prod.getPartNumber() +" NEW SIZE: " + products.size());
products.get(1).setFlex1("UK Product");
products.add(new Product("Steel Hinges", "4\"", "India", "", cat));
System.out.println("Updated products: " + products.size());
cat.setProducts(products);
im.udpateCategory(cat);
System.out.println("Category updated");
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The client side result show correctly that product entity was removed
Found Category: Hinges catNo: 7
Found products: 3
Removed: Steel Hinges 2" NEW SIZE: 2
Updated products: 3
Category updated
But the database had new Products added, modified products updated but removed product not deleted from database.
Strangely if code "cat.setProducts(products);" is commented in the client program, then database will show the removed entity has catNo NULL but not removed. But with above line commented, the new entity is not added or modified entity is not updated. Is this bug as there are no error message thrown on server.
I'll appreciate someone help. I want the dynamism to add, remove or update entity in OneToMany relation.
Thanks
Murtuza