Monday, 24 December 2012
JPA Troubleshooting: "org.hibernate.PropertyNotFoundException: Could not find a setter for property myProp in class mypackage.Foo"
Sunday, 12 February 2012
JPA: How to know if a OptimisticLockException os thrown
try {
//access the DAO...
}
catch(Exception e) {
if("nested exception is javax.persistence.OptimisticLockException".equals(e.getMessage()))
//then it is a OptimisticLockException
}
See also...
See how to implement VersioningWednesday, 1 February 2012
JPA: How to implement Versioning (@Version)
@Entity
public class Foo {
// ...
prive Long version;
@Version
public Long getVersion() { return version; }
public void setVersion(Long version) { this.version = version; }
// ...
}
On each transaction commit if the entity is modified (persist or merge) the version column is increased by one.
Other possibilities
Instead of a Long you could use a Integer or a Date..but Date has performance problems and does not guarantee good behavior if two commits are happened with milliseconds time difference (see http://swinbrain.ict.swin.edu.au/wiki/Implementing_Concurrency_Controls_using_Hibernate).See also...
If you get StaleObjectStateException or OptimisticLockException then make sure that you don't persist the loading time of the entity (see http://micharg.blogspot.com/2012/02/jpaversioning-thrown.html)How to catch a OptimisticLockException
JPA:Versioning: thrown OptimisticLockException or StaleObjectStateException
entityManager.find()) an entity from the db I updated an attributed of it (loadDate)...
@PostLoad
public void postLoad() throws Exception {
loadDate = new Date();
}
So the entity was changed and it was automatically merged when the transactions contained the entityManager.find() was finished (commited). Pretty silly...
For more info on the above technique of persisting the loading time of an entity see http://micharg.blogspot.com/2012/02/jpa-how-to-persist-loading-of-entity.html
JPA: How to persist the loading time of an entity
@Entity
public class GenericEntity implements Serializable {
// ...
@Column(name="LOAD_DATE")
@Temporal(TemporalType.TIMESTAMP)
public Date getLoadDate() { return loadDate; }
public void setLoadDate(Date loadDate) { this.loadDate = loadDate; }
@PostLoad
public void postLoad() throws Exception {
loadDate = new Date();
}
// ...
}
Monday, 30 January 2012
JPA: @OneToMany error: Field 'usersB_ID' doesn't have a default value
Code with error:
@Entity
public class Users {
@OneToMany
public Set getUsersA() { return usersA; }
@OneToMany
public Set getUsersB() { return usersB; }
}
Problem description: In a @OneToMany relationship is you don't specify a join table then JPA creates one with the combined name of the outer class and the return type of the getter, i.e. in our case Users_User.
Since usersA and usersB are of the same class then JPA creates only one join table. When we add a User in (e.g.) usersA and persist/merge Users in db then an sql cmd such as the following is executed:
insert into Users_user (Users_ID, users_ID) values (1,3)but Users_user has 3 columns: id, FK to User class because of getUsersA(), FK to User class because of getUsersB(). But the 3rd column remains null in the previous sql statement and therefore an error is thrown: Field 'usersB_ID' doesn't have a default value
Solution: Create 2 join tables
@Entity
public class Users {
@OneToMany
@JoinTable
(
name="Users_usersA",
joinColumns={ @JoinColumn(name="Users_ID", referencedColumnName="ID") },
inverseJoinColumns={ @JoinColumn(name="USER_ID", referencedColumnName="ID") }
)
public Set getUsersA() { return usersA; }
@OneToMany
@JoinTable
(
name="Users_usersB",
joinColumns={ @JoinColumn(name="Users_ID", referencedColumnName="ID") },
inverseJoinColumns={ @JoinColumn(name="USER_ID", referencedColumnName="ID") }
)
public Set getUsersB() { return usersB; }
}
Sunday, 29 January 2012
JPA Criteria: Safe JPA Criteria for Enum
public enum FooType {
//...
}
Entity Foo (containing attribute FooType):
@Entity
public class Foo {
protected FooType type;
@Enumerated(EnumType.STRING)
public FooType getType() { return type; }
public void setType(FooType type) { this.type = type; }
}
DAO method to find all Foos by FooType:
public ListfindAllFooByType(FooType type) { CriteriaBuilder cb = getEntityManager().getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(Foo.class); Root invitation = cq.from(Foo.class); cq.where( cb.equal(invitation.get(Foo_.type), type)); cq.select(invitation); TypedQuery typedQuery = getEntityManager().createQuery(cq); return typedQuery.getResultList(); }
References
http://blogs.oracle.com/Lance/entry/generating_the_jpa_2_0JPA: How to add unique constraint on an attribute
References
http://stackoverflow.com/questions/1839186/unique-constraint-check-in-jpaOopen Issue
Open issue:An issue yet unsolved is how to catch properly the exception reason and present it to the user. For example when a user signs up I do not want to allow the use of an existing username.Friday, 27 January 2012
JPA/Hibernate error: cannot simultaneously fetch multiple bags
References
First read StackOverflow for the reason behind the error (tip: JPA annotations are parsed not to allow more than 2 eagerly loaded collection). Definitely read the excellent article of explodingjava about the problem and an in depth analysis how to solve it.JPA: where by enum
@Entity
class Foo implements Serializable {
// ....
private MyEnum e;
@Enumerated(EnumType.STRING)
public MyEnum getE() {
return e;
}
public void setE(MyEnum e) {
this.e = e;
}
// ....
}
JPA Criteria query: find all Foo containing MyEnum==method parameter e:
public ListfindByMyEnum(MyEnum e) { CriteriaBuilder cb = getEntityManager().getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(Foo.class); Root foo = cq.from(Game.class); cq.where( cb.equal(game.get(Foo_.e), e) ); cq.select(foo); TypedQuery typedQuery = getEntityManager().createQuery(cq); return typedQuery.getResultList(); }
JPA+Hibernate: How to show the bounded values instead of the question marks on the queries
#log4j.logger.org.hibernate=INFO, hb log4j.logger.org.hibernate.SQL=DEBUG log4j.logger.org.hibernate.type=TRACE
#log4j.logger.org.hibernate.hql.ast.AST=info
#log4j.logger.org.hibernate.tool.hbm2ddl=warn
#log4j.logger.org.hibernate.hql=debug
#log4j.logger.org.hibernate.cache=info
#log4j.logger.org.hibernate.jdbc=debug
#log4j.appender.hb=org.apache.log4j.ConsoleAppender
#log4j.appender.hb.layout=org.apache.log4j.PatternLayout
#log4j.appender.hb.layout.ConversionPattern=HibernateLog --> %d{HH:mm:ss} %-5p %c - %m%n
#log4j.appender.hb.Threshold=TRACE
Rereferences
http://stackoverflow.com/questions/2536829/hibernate-show-real-sqlThursday, 19 January 2012
Ignore a parent class when Serializing to XML
// "implements Serializable" gives Exception #1 public class GenericEntityImplimplements Serializable { // gives Exception #2 protected PK id = null; // gives Exception #3 protected Locale locale; }
@XmlRootElement(name="child") public class Child extends GenericEntityImplException:{ }
Caused by: com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 3 counts of IllegalAnnotationExceptions java.io.Serializable is an interface, and JAXB can't handle interfaces. this problem is related to the following location: at java.io.Serializable at public java.io.Serializable core.domain.GenericEntityImpl.getId() at core.domain.GenericEntityImpl at foo.Child java.io.Serializable does not have a no-arg default constructor. this problem is related to the following location: at java.io.Serializable at public java.io.Serializable core.domain.GenericEntityImpl.getId() at core.domain.GenericEntityImpl at foo.Child java.util.Locale does not have a no-arg default constructor. this problem is related to the following location: at java.util.Locale at public java.util.Locale core.domain.GenericEntityImpl.getLocale() at core.domain.GenericEntityImpl at foo.ChildCode without error (recommendation link):
@XmlAccessorType(XmlAccessType.NONE) public class GenericEntityImplimplements Serializable { // same }
@XmlRootElement(name="child") public class Child extends GenericEntityImplNotes: Tried adding on GenericEntityImpl the annotation @XmlTransient but didn't work. Also tried adding to Child the annotation @XmlAccessorType(XmlAccessType.FIELD) and moving all the JAXB annotation on the attributes but didn't work either (see this recommendation); note that the JPA annotations are on the methods.{ // same }
Friday, 23 December 2011
JPA: how to save a List of Blob
@Entity
@Table(name="FOO")
public class FOO {
// Item should implement Serializable; do not
// add here any JPA annotations
public ArrayList- getItems() {...}
}
// no JPA annotations
public class Item implements Serializable {
}
References
StackOverflowWednesday, 14 December 2011
JPA: DO NOT PUT CascadeType in both parts of a two class-relationship (1-1,m-n,n-m,whatever)!!!
@OneToMany(targetEntity=Toy.class, mappedBy="Toy", fetch=FetchType.EAGER)//CascadeType here? public SetToy.javagetToys() { return toys; }
@ManyToOne//CascadeType here?
@JoinColumn(name="BOY_ID")
public Boy getBoy() {
return boy;
}
Where should I put the Cascade? In Boy or in Toy?Or in both?
ANSWER: only in one of them. If you put it in both then one will override the other!!
Example #1 (wrong: overriding cascade)
cascade=CascadeType.ALL in Boy:getToys()
cascade={CascadeType.PERSIST,CascadeType.MERGE} in Toy::getBoy()
// throws exception "Deleted entity passed to persist" entityManager.deleteById(toy.getId());
Example #2 (right)
cascade={CascadeType.PERSIST,CascadeType.MERGE} only in Toy::getUser()
//works fine :) entityManager.deleteById(toy.getId());
Sunday, 27 November 2011
JSF error: on ElementCollection of enum Caused by: java.lang.IllegalArgumentException: Unknown name value for enum class javax.persistence.EnumType: MY_TYPE_A
Wrong (targetClass = EnumType.class):
@ElementCollection(targetClass = EnumType.class) @JoinTable(name = "A__LINK__MY_TYPE", joinColumns = @JoinColumn(name = "MY_TYPE_FK")) @Enumerated(EnumType.STRING) public SetgetMyTypes() { return myTypes; }
Correct (targetClass = MyType.class):
@ElementCollection(targetClass = MyType.class) @JoinTable(name = "A__LINK__MY_TYPE", joinColumns = @JoinColumn(name = "MY_TYPE_FK")) @Enumerated(EnumType.STRING) public SetgetMyTypes() { return myTypes; }
JPA: FetchType default values
- @OneToOne: EAGER
- @OneToMany: LAZY
- @ManyToOne: EAGER
- @ManyToMany: LAZY
References
@OneToOne @OneToMany @ManyToOne @ManyYoManyThursday, 24 November 2011
JPA/SQL: a column cannot have the name "references"
private String references;
public String getReferences() {
return references;
}
public void setReferences(String references) {
this.references = references;
}
translates into the following SQL:
create table ...,references varchar(255),and MySLQ thinks that the column is a Foreign Key...which is invalid syntax... In order to solve this just rename references into (eg) ref
JPA: Collection of enums
Wrong annotations
@OneToMany(cascade=CascadeType.ALL) @Enumerated(EnumType.STRING) public ListgetMyEnum() { ... }
Right annotations
@ElementCollection @JoinTable(name = "DB_MYCLASS__LINK__MYENUM", joinColumns = @JoinColumn(name = "MYENUM_FK")) @Enumerated(EnumType.STRING) public ListgetMyEnum() { ... }
Monday, 14 November 2011
Friday, 11 November 2011
JPA/Hibernate reminder: initialize all fields! if not then set it to null
If I don't initialize a field then I get a transient exception.
If I initialized it by calling a class constructor then the new object is
persisted to db. What if I want this Foreign Key (FK) to be empty?
solution: If I initialize it to null then everything it's ok (why?).
Note: If I remove the CascadeType.ALL then I get again the transient exception
References
http://cagataycivici.wordpress.com/2005/11/15/pivefacedwith/