JPA, compound key with foreign keys + persist oneToMany - jpa-2.0

I'm trying to do something with JPA that'll use a lot on a project but I'm stuck.
I have 2 entities + a kind of "glue" entity, I'll call them
ClassA
ClassB
Glue
I want to add a new ClassA with new Glues set in it's list, ClassB's already exist.
That would do something like :
ClassA 1 | Glue 1 1 | ClassB 1
ClassA 1 | Glue 1 2 | ClassB 2
ClassA 1 | Glue 1 3 | ClassB 3
ClassA 1 | Glue 1 4 | ClassB 4
So as said ClassA and all Glues are to be inserted, ClassA has a List with the new Glues to be inserted.
Here they are :
#Entity
public class ClassA implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
(...)
#OneToMany(cascade = CascadeType.ALL, mappedBy = "classA")
private List<Glue> glueList;
(...)
}
#Entity
public class ClassB implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
(...)
}
#Entity
public class Glue implements Serializable {
#EmbeddedId
protected GluePK gluePK;
#JoinColumn(name = "id_class_a", referencedColumnName = "id", nullable = false, insertable = false, updatable = false)
#ManyToOne(optional = false)
private ClassA classA;
#JoinColumn(name = "id_class_b", referencedColumnName = "id", nullable = false, insertable = false, updatable = false)
#ManyToOne(optional = false)
private ClassB classB;
(...)
}
#Embeddable
public class GluePK implements Serializable {
#Basic(optional = false)
#NotNull
#Column(name = "id_class_a", nullable = false)
private int idClassA;
#Basic(optional = false)
#NotNull
#Column(name = "id_class_b", nullable = false)
private int idClassB;
(...)
}
When I try to persist my ClassA I'm getting something like :
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:
Cannot add or update a child row: a foreign key constraint fails (bdd.glue, CONSTRAINT constraint_name FOREIGN KEY (id_class_a) REFERENCES ClassA (id) ON DELETE NO ACTION ON UPDATE NO ACTION)
I understand that he complains that Glues dont have ClassA's reference set but I'd like him to fill it just then he persists ClassA.
Is this achievable?
If not what's the best way to do it?
I'd like to stay on JPA without any specific vendor tricks (I'm using eclipselink) but if some vendor can do it easily I'll go for it.
Thanks!

I would remove the EmbeddedId, use an IdClass instead and just add the #Id to the #ManyToOne mappings.
See,
http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#JPA_2.0
Or maybe even give Glue an id of its own.
You could also remove the insertable = false, updatable = false from the #ManyToOne and move them to the EmbeddedId.

Related

Hibernate criteria cannot fetch rows could not resolve property

Hi i have these 2 basic entity mapping for postgresql db, and i have wrote criteria for
fetching all activated user which have same key it is showing this error
org.hibernate.QueryException: could not resolve property: key.id of: com.sar.dfsapp.modal.ActivatedUser
#Entity
#Table(name = "activated_user")
public class ActivatedUser implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false, length = 11)
private long id;
#ManyToOne
#JoinColumn(name = "key_id", nullable = false)
private Key key;
}
#Entity
#Table(name = "key")
public class Key implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false, length = 11)
private long id;
#Column(name = "key_code", nullable = false)
private String keyCode;
}
Below is my criteria i have tried.
Criteria c = getSession().createCriteria(ActivatedUser.class);
c.add(Restrictions.eq("key.id", id));
List<ActivatedUser> result = c.list();
try this :
Criteria c = getSession().createCriteria(ActivatedUser.class);
Criteria keyCriteria = criteria.createCriteria("key", CriteriaSpecification.INNER_JOIN);
keyCriteria.add(Restrictions.eq("id", id));
List<ActivatedUser> result = c.list();
it there the same error ?

JPA Cascading removal of parent and Child

I'm trying to learn and understand JPA, and just have a couple of questions regarding deleting a parent and its children in one go. I'm using OpenJPA and EJB3. I have two entities, a Category and a Product. A Category contains many products and a product has a reference to its parent category. The category's list of products is set to cascade.
//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);
}
}
}
If I use the following code in the deleteCategory method the EJB then I cannot delete the parent and children as I get an Optimistic Locking exception (An optimistic lock violation was detected when flushing object instance "entity.Product-101" to the data store. This indicates that the object was concurrently modified in another transaction.) - complaining about flushing the product child to the data store
Category actualCat = entityManager.find(Category.class, category.getCategoryid());
if (products != null) {
actualCat.getProducts().clear();
}
entityManager.remove(actualCat);
However, if I use the following code in the deleteCategory method then I can delete the parent and children...but only if I call entityManager.refresh(actualCat) after removing the children and before removing the parent (otherwise I get an optimistic locking exception). Could somebody please explain to me why this is the case and also what the correct/best way of doing a cascading delete with OpenJPA V2 would be?
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);
Thanks in advance for your help
Fais
Addition
Here is the db creation script:
--
CREATE SCHEMA "DB2ADMIN";
CREATE TABLE "DB2ADMIN"."CATEGORY" (
"CATEGORYID" INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY ( START WITH 1 INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 NO CYCLE CACHE 20),
"NAME" VARCHAR(50) NOT NULL
)
DATA CAPTURE NONE;
CREATE TABLE "DB2ADMIN"."PRODUCT" (
"PRODUCTID" INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY ( START WITH 1 INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 NO CYCLE CACHE 20),
"CODE" CHAR(15) NOT NULL,
"NAME" VARCHAR(50) NOT NULL,
"DESCRIPTION" VARCHAR(200) NOT NULL,
"WEIGHT" FLOAT(53) NOT NULL,
"CATEGORYID" INTEGER NOT NULL
)
DATA CAPTURE NONE;
ALTER TABLE "DB2ADMIN"."CATEGORY" ADD CONSTRAINT "CATEGORY_PK" PRIMARY KEY
("CATEGORYID");
ALTER TABLE "DB2ADMIN"."PRODUCT" ADD CONSTRAINT "PRODUCT_PK" PRIMARY KEY
("PRODUCTID");
ALTER TABLE "DB2ADMIN"."PRODUCT" ADD CONSTRAINT "PRODUCT_CATEGORY_FK" FOREIGN KEY
("CATEGORYID")
REFERENCES "DB2ADMIN"."CATEGORY"
("CATEGORYID")
ON DELETE CASCADE;

JPA StackOverflowError when loading data in relationship tables

I'm trying to implement loading in three tables (the beginning of the problem with mapping)
Products:
#Entity
#Table(name = "products")
public class Product implements Serializable {
#Id
#Column(name = "id")
private Integer id;
#OneToMany(mappedBy = "property", fetch = FetchType.LAZY)
private Collection<ProductProperty> productPropertyCollection;
...
}
Properties:
#Entity
#Table(name = "properties")
public class Property implements Serializable {
#Id
#Column(name = "id")
private Integer id;
#OneToMany(mappedBy = "property", fetch = FetchType.LAZY)
private Collection<ProductProperty> productPropertyCollection;
...
}
Product_Property
#Entity
#Table(name = "product_property")
public class ProductProperty implements Serializable {
#EmbeddedId
protected ProductPropertyPK productPropertyPK;
#MapsId(value = "propertyId")
#JoinColumn(name = "property_id", referencedColumnName = "id")
#ManyToOne()
private Property property;
#MapsId(value = "productId")
#JoinColumn(name = "product_id", referencedColumnName = "id")
#ManyToOne()
private Product product;
...
}
#Embeddable
public class ProductPropertyPK implements Serializable {
#Basic(optional = false)
#NotNull
#Column(name = "product_id", insertable = false, updatable = false)
private int productId;
#Basic(optional = false)
#NotNull
#Column(name = "property_id", insertable = false, updatable = false)
private int propertyId;
...
}
It works fine for 1, 10, 100 products, but somewhere there is an error, because for 1000 and more products throws error:
Caused by: java.lang.StackOverflowError
at java.util.HashMap.getEntry(HashMap.java:443)
at java.util.HashMap.containsKey(HashMap.java:434)
at java.util.HashSet.contains(HashSet.java:201)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.discoverAndPersistUnregisteredNewObjects(UnitOfWorkImpl.java:4141)
at org.eclipse.persistence.mappings.ObjectReferenceMapping.cascadeDiscoverAndPersistUnregisteredNewObjects(ObjectReferenceMapping.java:938)
at org.eclipse.persistence.mappings.ObjectReferenceMapping.cascadeDiscoverAndPersistUnregisteredNewObjects(ObjectReferenceMapping.java:916)
at org.eclipse.persistence.internal.descriptors.ObjectBuilder.cascadeDiscoverAndPersistUnregisteredNewObjects(ObjectBuilder.java:1964)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.discoverAndPersistUnregisteredNewObjects(UnitOfWorkImpl.java:4178)
at org.eclipse.persistence.mappings.CollectionMapping.cascadeDiscoverAndPersistUnregisteredNewObjects(CollectionMapping.java:426)
at org.eclipse.persistence.internal.descriptors.ObjectBuilder.cascadeDiscoverAndPersistUnregisteredNewObjects(ObjectBuilder.java:1964)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.discoverAndPersistUnregisteredNewObjects(UnitOfWorkImpl.java:4178)
at org.eclipse.persistence.mappings.ObjectReferenceMapping.cascadeDiscoverAndPersistUnregisteredNewObjects(ObjectReferenceMapping.java:938)
at org.eclipse.persistence.mappings.ObjectReferenceMapping.cascadeDiscoverAndPersistUnregisteredNewObjects(ObjectReferenceMapping.java:916)
at org.eclipse.persistence.internal.descriptors.ObjectBuilder.cascadeDiscoverAndPersistUnregisteredNewObjects(ObjectBuilder.java:1964)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.discoverAndPersistUnregisteredNewObjects(UnitOfWorkImpl.java:4178)
at org.eclipse.persistence.mappings.CollectionMapping.cascadeDiscoverAndPersistUnregisteredNewObjects(CollectionMapping.java:426)
at org.eclipse.persistence.internal.descriptors.ObjectBuilder.cascadeDiscoverAndPersistUnregisteredNewObjects(ObjectBuilder.java:1964)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.discoverAndPersistUnregisteredNewObjects(UnitOfWorkImpl.java:4178)
at org.eclipse.persistence.mappings.ObjectReferenceMapping.cascadeDiscoverAndPersistUnregisteredNewObjects(ObjectReferenceMapping.java:938)
at org.eclipse.persistence.mappings.ObjectReferenceMapping.cascadeDiscoverAndPersistUnregisteredNewObjects(ObjectReferenceMapping.java:916)
at org.eclipse.persistence.internal.descriptors.ObjectBuilder.cascadeDiscoverAndPersistUnregisteredNewObjects(ObjectBuilder.java:1964)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.discoverAndPersistUnregisteredNewObjects(UnitOfWorkImpl.java:4178)
...
when i'm creating ProductProperty, i'm setting product and property in ProductProperty, and adding to collection for bidirection in Product and Property.
where i could make a mistake?
Looks like your object model complexity or depth is just difficult to traverse within your JVM's stack limits. As it is, every entity seems reachable from every other entity, which causes problems when traversed recursively. Try increasing the -Xss setting. You might also reduce the interconnectivity, such as removing one of the OneToMany mappings and query for it directly instead of storing it in the Product or Property mapping. You might also file an enhancement with EclipseLink to traverse the object graph using a stack instead of recursively.

hibernate jpa join two table with another table

I have two table A and B
Table A:
ID_A
name
table B
ID_B
name
I joined both by a third table C table with their primary key
table C
ID_C
ID_A
ID_B
I'd like to know this relationship in jpa mapping to retrieve the list of object B inside object A
thank you,
Class A has list of C objects.
class A{
#Id
private Long Id;
#Column(name = "name_a", length = 5)
private Strin name_a;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "a", fetch = FetchType.LAZY)
private List<C> cList;
}
class B{
#Id
private Long Id;
#Column(name = "name_b", length = 5)
private String name_b;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "b", fetch = FetchType.LAZY)
private List<C> cList;
}
This is join table.Class C has A object and B object.
class C{
#Id
private Long id;
#JoinColumn(name = "id_a", referencedColumnName = "id", nullable = false)
#ManyToOne(optional = false, fetch = FetchType.LAZY)
private A a;
#JoinColumn(name = "id_b", referencedColumnName = "id", nullable = false)
#ManyToOne(optional = false, fetch = FetchType.LAZY)
private B b;
}
I have find a good example here http://viralpatel.net/blogs/hibernate-many-to-many-annotation-mapping-tutorial/

Not Null Property Exception with JPA onetoone mapping

I am trying my way around JPA but I cant get this to work the way I understand them.
Its the onetoone bidirectional mapping between an Order and an OrderInvoice class which is a required
association
My entities are marked as this
#Entity
#Table(name = "Orders")
public class Order {
#Id
#GeneratedValue
#Column(name = "ORDER_ID")
private int orderId;
#OneToOne(optional=false,cascade=CascadeType.ALL, mappedBy="order", targetEntity=OrderInvoice.class)
private OrderInvoice invoice;
}
#Entity
#Table(name = "ORDER_INVOICE")
public class OrderInvoice {
#Id
#GeneratedValue
#Column(name = "INVOICE_ID", nullable = false)
private int invoiceId;
#OneToOne(optional = false)
#JoinColumn(name="ORDER_ID")
private Order order;
}
My test class is like this.
#Test
public void createOrder() {
Order order = createOrderImpl();
assertNotNull(order);
}
private Order createOrderImpl() {
OrderInvoice orderInvoice = new OrderInvoice(new Date(), 100.0, null,
null, new Date());
Order order = new Order(100.0, "JOHN Doe's Order", new Date(), new Date(),orderInvoice);
orderDao.create(order);
return order;
}
But I am encountering below problem when I run my Test
javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null property references a null or transient value: order.OrderInvoice.order
at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:614)
Caused by: org.hibernate.PropertyValueException: not-null property references a null or transient value: order.OrderInvoice.order
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:95)
try to
orderInvoice.setOrder(order);
orderDao.create(order);