I'm using hibernate JPA (without Spring) and it's working well, but I have come across a problem which has stumped me for the last 3 days.
I have written some generic DAO classes and am using them to persist my objects. They all work fine, except for one class of object which is not being persisted. No exceptions are thrown. I've tried debugging inside the hibernate code and found that the reason the entity is not being persisted is that in the org.hibernate.event.def.DefaultFlushListener onFlush() method, source.getPersistenceContext().getEntityEntries().size() == 0 so no flushing is performed. But I can't work out why that would be the case.
The classes in question look like this:
#Entity
#Table(name="er_batch_runs")
public class BatchRun implements Serializable, Comparable<BatchRun>, BatchBean {
private Long runId;
private String hostname;
.... more field here
#Override
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="runseq")
#SequenceGenerator(name="runseq", sequenceName="er_batch_runs_seq", allocationSize=1 /*, initialValue = 10*/)
#Column(name="batch_run_id")
public Long getId() {
return runId;
}
public void setId(long runId) {
this.runId = runId;
}
#Column(name="hostname")
public String getHostname() {
return hostname;
}
public void setHostname(String hostname) {
this.hostname = hostname;
}
pretty straightforward hibernate JPA stuff.
Here's another class:
#Entity
#Table(name="er_batch_txns")
public class BatchTxn implements Serializable, Comparable<BatchTxn>, BatchBean {
private long id;
.......... more fields
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="batchtxnseq")
#SequenceGenerator(name="batchtxnseq", sequenceName="ER_BATCH_TXNS_SEQ", allocationSize=1/*00, initialValue = 10*/)
#Override
#Id
#Column(name="BATCH_TXN_ID")
public Long getId() {
return id;
}
the BatchBean interface is what allows me to use generic DAOs like this:
public Long create(BatchBean newInstance) {
getOpenEntityManager().persist(newInstance);
logger.debug("hopefully created {} with id {}",newInstance.getTypeName(),newInstance.getId());
return newInstance.getId();
}
Transactions are being handled manually. I've set the flush type to COMMIT (ie flush on commit) and when I've completed the persist, I do a commit. After the persist, then BatchTxn object has been assigned a primary key from the sequence. When I debug hibernate I can see that getPersistenceContext().getEntityEntries() returns an empty Map.
so the question is why the BatchTxn is not being persisted by the commit, when the BatchRuns, and 5 other classes which implement BatchBean, are?
I'm using hibernate 3.6.0 Final
The only thing I saw that is suspected in your code is this in the BatchTxn class:
private long id;
This will be set automatically to zero. Maybe you should use Long (with a capital letter)?
Related
I have an TimelineEntity entity, that uses HoTimelineType enum with custom integer value. That custom integer value is stored in the database. Implemented via Using #PostLoad and #PrePersist Annotations
Sprint JPA Repository is used to save and get entities.
Here is the issue:
#Entity
#Table(name = TABLE_NAME)
#IdClass(TimelineKey.class)
public class TimelineEntity {
public interface Persistence {
String TABLE_NAME = "timelines";
}
#Id
#Column(name = "node_id")
private Long nodeId;
#Id
#Column(name = "timeline_id")
private Long timelineId;
#Column(name = "ho_timeline_type")
private Integer hoTimelineTypeValue;
#Transient
private HoTimelineType hoTimelineType;
public Long getNodeId() {
return nodeId;
}
public void setNodeId(Long nodeId) {
this.nodeId = nodeId;
}
public Long getTimelineId() {
return timelineId;
}
public void setTimelineId(Long timelineId) {
this.timelineId = timelineId;
}
public HoTimelineType getHoTimelineType() {
return hoTimelineType;
}
public void setHoTimelineType(HoTimelineType hoTimelineType) {
this.hoTimelineType = hoTimelineType;
}
public Integer getHoTimelineTypeValue() {
return hoTimelineTypeValue;
}
public void setHoTimelineTypeValue(Integer hoTimelineTypeValue) {
this.hoTimelineTypeValue = hoTimelineTypeValue;
}
#PostLoad
private void postLoad() {
this.hoTimelineType = HoTimelineType.of(hoTimelineTypeValue);
}
#PrePersist
private void prePersist() {
this.hoTimelineTypeValue = hoTimelineType.getValue();
}
}
#Eager
public interface TimelineEntityRepository extends JpaRepository<TimelineEntity, TimelineKey> {
List<TimelineEntity> findByNodeId(Long nodeId);
}
#Autowired
private TimelineEntityRepository timelineEntityRepository;
...
TimelineEntity newTE = new TimelineEntity();
newTE.setNodeId(10L);
newTE.setTimelineId(22L);
newTE.setHoTimelineType(HoTimelineType.TYPE_1);
newTE = timelineEntityRepository.save(newTE);
When the newTE entity is saved, prePersist is invoked, and inside this method, the hoTimelineType is null and I get NPE. nodeId and timelineId are not nulls. If I stay with a debugger on the last line, outside of prePersist, I see that hoTimelineType has the value, I set before.
When I load entities, inserted with test data, everything works fine and both hoTimelineType and hoTimelineTypeValue have not nullable values.
I skipped the code of TimelineKey and HoTimelineType to simplify the example. Can add it, if needed.
What could reset hoTimelineType? What do I miss?
It seems there is no way to control the saving behaviour of spring jpa repository proxy.
Possible solutions for issue:
Via javax.persistence.Converter. It is pretty clear, the structe of an entity is simple. Can confirm it works fine with Spring Jpa Repository generation.
Explicitely set hoTimelineTypeValue before you save an entity. Error-prone solution. Everytime you save an entity you must think about the difference between the hoTimelineTypeValue and hoTimelineType.
You could enrich setters and getters of the entity class, to explicitely control the consistency between the fields. It makes implementation of entity classes not so obvious. You get more compicated solution for nothing. As a result error-prone solution. Do not recommend it as well.
Cause of disadvantages of #2 and #3 I do not provide examples. It makes no sense.
Example of the solution #1 can be found here: Using JPA 2.1 #Converter Annotation
I have these two entities
#Entity
#Table(name = "CallSession")
public class CallSession implements Serializable {
private long id;
private List<CallParticipant> members;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
#OneToMany(mappedBy = "callSession", fetch = FetchType.LAZY)
public List<CallParticipant> getMembers() {
return members;
}
public void setMembers(List<CallParticipant> members) {
this.members = members;
}
}
#Entity
#Table(name = "CallParticipant")
public class CallParticipant implements Serializable {
private long id;
private CallSession callSession;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
#ManyToOne
public CallSession getCallSession() {
return callSession;
}
public void setCallSession(CallSession callSession) {
this.callSession = callSession;
}
}
but when I invoke callSession.getMembers() method,
I get this Exception:
Unable to evaluate the expression Method threw 'org.hibernate.LazyInitializationException' exception.
I cannot make a head or tail of why I get this error? Why do I get this error and how can I fix this?
I’m going to start by assuming you want your collection to be lazy loaded.
Hibernate’s session can be closed in a lot of contexts, and once the session is closed, it won’t be able to fetch any lazy loaded collections.
Generally Hibernate is very good at keeping sessions open for the lifecycle of HTTP threads in a web app context (Spring’s “open session in view”). Reasons the session could be closed include that the object was handed off from one thread to another, or the object was cached and then accessed by another thread.
But it can be more difficult if your code is running in a job or a non-web application context.
Fixes
1. Create a repository method to explicitly fetch the collection
Using #Query and join fetch, add a repository method that explicitly eager-loads the collection.
2. Call .toString() on the collection after fetching the object.
This is a nasty hack that I’ve seen many people use in the real world before. Basically, before caching the object or handing it off to an executor or somewhere where it would be accessed by another thread, call .toString() on the collection to load it. Usually leave a comment explaining why.
3. Add #Transactional to a method that is both fetching the data and accessing the collection
This has many implications other than keeping the session alive (e.g. database operations succeed and fail together), but can be a quick fix to keep the session alive in for example a job method.
Hope this helps.
I'm building one application using JPA, I want to have a parent entity called "BaseEntity" with the attribute ID and then the rest of the entities extending this entity and then having their own attributes. The field id in the parent class is protected. However when I start the server I'm getting the following error:
Caused by: org.hibernate.AnnotationException: No identifier specified for entity: com.fgonzalez.domainmodel.User
Of course if I place the id field in the class User, it is working fine but this is not what I want. The weird thing is if I use xml files for the hibernate mappings instead of JPA, it works fine, but not with JPA. Any idea where can be the problem? Attached the code:
Base Entity:
public class BaseEntity implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name="id")
protected Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
And User entity:
#Entity
#Table(name="users")
public class User extends BaseEntity{
/**
*
*/
private static final long serialVersionUID = 1L;
/**
*
*/
#Column(name="EMAIL",nullable=false,length=50,insertable=true,updatable=true)
private String email;
#Column(name="PASSWORD",nullable=false,length=50,insertable=true,updatable=true)
private String password;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email=email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Thank you in advance!!
You can't do that this way: BaseEntity isn't an #Entity, so #Id shouldn't even be processed.
If Hibernate does process it while using xml, that's probably a non-portable specificity.
You could implement some entity hierarchy, but I wouldn't do it in this case. You can only extend once, and this doesn't look like a real hierarchy: only one root, shared by every class?
You can find more information on entity inheritance here: http://docs.oracle.com/javaee/6/tutorial/doc/bnbqn.html
You could use compositions instead of inheritance. In this case, just annotate your User class (which wouldn't be an #Entity) with #Embeddable, and have a field annotated with #EmbeddedId on the using class.
Still, I wouldn't do that: it seems more DRY, but it has no more benefits that replacing String everywhere with something else just to not repeat yourself (which you would then do anyway).
I would just have an #Id Long id; field in every entity, freeing them from hierarchy hell. It looks more boilerplate, but will be much easier in the long term, with no obvious disadvantage.
If you are going implement inheritance in JPA, you are not suppose to do like in java. JPA got its own implementation strategies. Have a look here and choose the one that best suits your need
I have one entity having composite key and I am trying to persist it by using spring data jpa repository to mysql databse as given below:
#Embeddable
public class MobileVerificationKey implements Serializable{
private static final long serialVersionUID = 1L;
#Column(name="CUSTOMERID")
private Long customerId;
#Column(name="CUSTOMERTYPE")
private Integer customerType;
#Column(name="MOBILE")
private Long mobile;
#Embeddable
public class MobileVerificationKey implements Serializable{
private static final long serialVersionUID = 1L;
#Column(name="CUSTOMERID")
private Long customerId;
#Column(name="CUSTOMERTYPE")
private Integer customerType;
#Column(name="MOBILE")
private Long mobile;
//getter and setters
}
And Entity as
#Entity
#Table(name="mobileverificationdetails")
public class MobileVerificationDetails {
#EmbeddedId
private MobileVerificationKey key;
#Column(name="MOBILETYPE")
private String mobileType;
#Column(name="MOBILEPIN")
private Integer mobilePin;
//getters and setters
}
My spring data jpa repository look like this:
public interface MobileVerificationDetailsRepository extends
CrudRepository<MobileVerificationDetails, MobileVerificationKey> {
#Override
MobileVerificationDetails save(MobileVerificationDetails mobileVerificationDetails);
#Override
MobileVerificationDetails findOne(MobileVerificationKey id);
}
Now if I am trying to add duplicate record with same key for original record and different values for other fields .when i try to insert second record it results in update of existing record with new values instead of throwing exception for violating primary key constraint...can any one please explain me this behavior.
The easiest (and least invasive) way to work around this is probably by making sure the id only gets set right before the persist. This can be achieved in a #PrePersist callback:
abstract class MobileVerificationDetails {
#EmbeddedId
private MobileVerificationKey id;
#PrePersist
void initIdentifier() {
if (id == null) {
this.id = … // Create ID instance here.
}
}
}
Alternatively to that you can enforce persist(…) being used by implementing Persistable and implementing isNew() accordingly. Make sure this method returns true on first insert. We usually see people holding a transient boolean flag that is updated in an #PostPersist/#PostLoad annotated method.
abstract class AbstractEntity<ID extends Serializable> implements Persistable<ID> {
private #Transient boolean isNew = true;
#Override
public boolean isNew() {
return isNew;
}
#PostPersist
#PostLoad
void markNotNew() {
this.isNew = false;
}
}
Spring Data Jpa Repository functionality is implemented via the SimpleJpaRepository class containing following save(..) method:
#Transactional
public <S extends T> S save(S entity) {
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
Thus the Spring Jpa Data Repository save(...) method merges an already existing entity.
Opposed to that the naked EntityManager#persist() throws an exception if invoked with already existing entity.
The problem might be solved by adding custom behavior to Spring Data Repository/ies. The custom behavior might be added using one of the approaches as described in 1.3.1 Adding custom behavior to single repositories with example here or in 1.3.2 Adding custom behavior to all repositories with example here. In both cases the custom behavior would include a new persist() method delegating to EntityManager#persist(). Note that in approach 1.3.2. you already have a EntityManager instance, in the approach 1.3.1 you are able to inject EntityManager instance using the #PersistenceContext.
Opposed to my comment I would recommend adding new method to the repository and not overwriting the existing save(...).
I use GWT and JPA for persistence. I have created a domain JPA enchanted classes, DAO's and RPC for communication between them. Everything works fine, through RPC the client sends the object to server but could not get response. Server cannot deserialize in a compatible way with the client side. So i cannot use the server callBack back to the client. The exception message is this:
The response could not be
deserialized,
com.google.gwt.user.client.rpc.SerializationException
Here's a sample code of one of my classes:
#Entity
#Table(name="course")
public class Course implements Serializable {
private static final long serialVersionUID = 1L;
private int courseId;
private String name;
private List<Group> groups;
private List<Module> modules;
public Course() {
}
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(unique=true, nullable=false)
public int getCourseId() {
return this.courseId;
}
public void setCourseId(int courseId) {
this.courseId = courseId;
}
#Column(nullable=false, length=100)
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
//bi-directional many-to-one association to Group
#OneToMany(mappedBy="course", fetch=FetchType.LAZY)
public List<Group> getGroups() {
return this.groups;
}
public void setGroups(List<Group> groups) {
this.groups = groups;
}
//bi-directional many-to-one association to Module
#OneToMany(mappedBy="course", fetch=FetchType.LAZY)
public List<Module> getModules() {
return this.modules;
}
public void setModules(List<Module> modules) {
this.modules = modules;
}
}
If i remove the relationships it work's fine. This is done because collections like lists, set's e.t.c are converted into hibernate objects that cannot be handled by GWT client side.
Well the problem is that my class has #OneToMany association to another class. If i remove the association it work's fine. But it's impossible to that, since I use a normalized relational database
If you're using GWT-RPC, make sure that all of the classes you're trying to serialize have a public default (no-argument) constructor and implement Serializable. If you have embedded classes, they must also have a no-arg constructor.
Once , I have prepared gwt-jpa sample for this question. It is just serialization of JPA entity.. It might give you a clue about what is wrong in your case..
I used Gilead and it fixed the issue.
Please check the corresponding post: GWT with JPA
got it working...after a redeploy of war again...strange..cant point to one specific thing (as i did clear browser cache/eclipse classes output/restart eclipse)
Apparently workaround seems to be try redeploying webapp whenever this issue occurs..