views:

59

answers:

1

Hi

I have some trouble understanding a JPA behaviour. Mabye someone could give me a hint. Situation:

Product entity:

@Entity
public class Product implements Serializable {
...
@OneToMany(mappedBy="product", fetch=FetchType.EAGER)
private List<ProductResource> productResources = new ArrayList<ProductResource>();
....
public List<ProductResource> getProductResources() {
    return productResources;
}
public boolean equals(Object obj) {
    if (obj == this) return true;
    if (obj == null) return false;
    if (!(obj instanceof Product)) return false;
    Product p = (Product) obj;
    return p.productId == productId;
}
}

Resource entity:

@Entity
public class Resource implements Serializable {
...
@OneToMany(mappedBy="resource", fetch=FetchType.EAGER)
private List<ProductResource> productResources = new ArrayList<ProductResource>();
...
public void setProductResource(List<ProductResource> productResource) {
    this.productResources = productResource;
}
public List<ProductResource> getProductResources() {
    return productResources;
}
public boolean equals(Object obj) {
    if (obj == this) return true;
    if (obj == null) return false;
    if (!(obj instanceof Resource)) return false;
    Resource r = (Resource) obj;
    return (long)resourceId==(long)r.resourceId;
}   
}

ProductResource Entity: This is a JoinTable (association class) with additional properties (amount). It maps Product and Resources.

@Entity
public class ProductResource implements Serializable {
...
@JoinColumn(nullable=false, updatable=false)
@ManyToOne(fetch=FetchType.EAGER, cascade=CascadeType.PERSIST)
private Product product;

@JoinColumn(nullable=false, updatable=false)
@ManyToOne(fetch=FetchType.EAGER, cascade=CascadeType.PERSIST)
private Resource resource;

private int amount;

public void setProduct(Product product) {
    this.product = product;
    if(!product.getProductResources().contains((this))){
        product.getProductResources().add(this);
    }   
}
public Product getProduct() {
    return product;
}
public void setResource(Resource resource) {
    this.resource = resource;
    if(!resource.getProductResources().contains((this))){
        resource.getProductResources().add(this);
    }       
}
public Resource getResource() {
    return resource;
}
...
public boolean equals(Object obj) {
    if (obj == this) return true;
    if (obj == null) return false;
    if (!(obj instanceof ProductResource)) return false;
    ProductResource pr = (ProductResource) obj;
    return (long)pr.productResourceId == (long)productResourceId;
}   
}

This is the Session Bean (running on glassfish).

@Stateless(mappedName="PersistenceManager")
public class PersistenceManagerBean implements PersistenceManager {

@PersistenceContext(unitName = "local_mysql")
    private EntityManager em;

public Object create(Object entity) {
    em.persist(entity);
    return entity;
}
public void delete(Object entity) {
    em.remove(em.merge(entity));
}
public Object retrieve(Class entityClass, Long id) {
    Object entity = em.find(entityClass, id);
    return entity;
}
public void update(Object entity) {
    em.merge(entity);
}
}

I call the session Bean from a java client:

public class Start {
public static void main(String[] args) throws NamingException {

    PersistenceManager pm = (PersistenceManager) new InitialContext().lookup("java:global/BackITServer/PersistenceManagerBean");

    ProductResource pr = new ProductResource();
    Product p = new Product();
    Resource r = new Resource();

    pr.setProduct(p);
    pr.setResource(r);

    ProductResource pr_stored = (ProductResource) pm.create(pr);

    pm.delete(pr_stored);
    Product p_ret = (Product) pm.retrieve(Product.class, pr_stored.getProduct().getProductId());
// prints out true ????????????????????????????????????
    System.out.println(p_ret.getProductResources().contains(pr_stored));
}
}

So here comes my problem. Why is the ProductResource entity still in the List productResources(see code above). The productResource tuple in the db is gone after the deletion and I do newly retrieve the Product entity. If I understood right every method call of the client happens in a new persistence context, but here i obviously get back the non-refreshed product object!?

Any help is appreciated

Thanks

Marcel

A: 

When I use the refresh method in the retrieve method it works.

public Object retrieve(Class entityClass, Long id) {
    Object entity = em.find(entityClass, id);
    // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    em.refresh(entity);
    // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    return entity;
}

So i assume the problem is the caching of eclipselink. If I use the create method on the ProductResource object, the Product and Resource objects are also stored (cascade=CascadeType.Persist). When I load the Product object again it comes out of the cache and therefore is not actual. So I should just also remove the ProductResource object in the lists of the Product and Resource object and do an update. Right? Calling refresh() in this place doesn't really make sense because it bypasses the caching.

Thanks Marcel

Marcel Menz