How do databases interact with jpa annotated pojo classes via Hibernate? - java

I'm a bit confused about how getters and setters in JPA annotated POJO classes interact with a proposed MySQL database via Hibernate.
I understand that you can have, for example, the following:
#Entity
#Table(appliesTo = "users")
public class UserDM implements UserIF, Serializable {
private static final long serialVersionUID = 1L;
private long id;
private String name;
private Date createDate;
#Id
#Column(name="id")
#GeneratedValue(strategy=GenerationType.AUTO)
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(final String n) {
name = n;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(final long time) {
createDate = new Date(time);
}
}
Why is the auto ID generation strategy associated with the Getter?
How does that method actually auto-incremeent the ID when a new user is stored?
What is the order of operations? The POJO is filled via setters (or maybe a constructor?) and then the info is acquired by hibernate via getters and then stored into the db?
Is it a good idea to have my "getCreateDate" method return a date, or is it best to have the fields in pojos map to MySQL-friendly fields? If I wanted to get a Date object from a timestamp ms value, would the best way to do that be to use a transient mapped function?

Why is the auto ID generation strategy associated with the Getter?
This is a matter of taste, most of the time. You can put the annotations on fields or accessors (getters), depending on how you prefer, as long as it's consistent (always on methods, or always on properties). By setting it to the property, Hibernate will use reflection to get access to the property (it's not as bad as it sounds). By setting it to the method, Hibernate will use it instead of reflection.
How does that method actually auto-incremeent the ID when a new user is stored?
Not sure at which level of details you want the answer, but to keep it short: Auto will use the best auto-increment strategy for the database server you are using. It could be "identity" for Sybase/SQLServer, it could be "sequence" for Oracle-like or it could be "auto increment" for MySQL. Common to all those cases is the fact that Hibernate will not know the ID until the database generates it. After triggering an "insert", Hibernate will use a standard JDBC method to access the "generated id"
What is the order of operations? The POJO is filled via setters (or maybe a constructor?) and then the info is acquired by hibernate via getters and then stored into the db?
Again, I don't know which level of details you want this, but yes, that's the order. You fill the POJO and you call the persist method on the EntityManager, passing this POJO as parameter. Hibernate will then call the getters (or access the properties) and will send this data to the database.
Is it a good idea to have my "getCreateDate" method return a date, or is it best to have the fields in pojos map to MySQL-friendly fields? If I wanted to get a Date object from a timestamp ms value, would the best way to do that be to use a transient mapped function?
Try to keep your application "database agnostic". So, don't make it "mysql friendly" if you don't really need. In general, using a java.util.Date in a field mapped with #Temporal(TIMESTAMP) would do, but if you need more "powerful" date/time objects, like Joda-time, you can also use it (as long as you tell Hibernate how to use it).

Related

How to map to an existing Hibernate model using jOOQ fetchInto()?

I'm trying to use the jOOQ fetchInto() method to map to an existing Hibernate model Organization (class and its inheritances are below).
Organization organization = jooq().select().from(ORGANIZATION).fetchOne().into(Organization.class);
The problem I have is that I can't really understand what happens in DefaultRecordMapper as I feel I'm not entirely familiar with all the terms that are used. I'm trying to figure out how it applies to the Hibernate classes that are in my codebase.
So far what I've tried:
Use the jOOQ generated POJO's to see if it retrieves and maps the data at all (works).
Add a constructor, getters and setters to the Organization Hibernate model.
Add #Column annotation to name in the Organization Hibernate model.
What works:
id field gets mapped correctly.
What doesn't work:
name field doesn't get mapped (null).
createdAt and modifiedAt fields do not get mapped (null).
My question is: Is there something I am overlooking with the mapping and what are the things I should look at concerning the classes, fields, constructors and annotations with Hibernate models? I want to eventually map all the Hibernate models in the codebase and use fetchInto to do that.
Thanks! :)
#Entity
public class Organization extends BaseModel {
#Required public String name;
//... a lot of other code
}
#MappedSuperclass
public class BaseModel extends Model {
/** The datetime this entity was first saved. Automatically set by a JPA prePersist */
#NoBinding
#Column
#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
public DateTime createdAt;
/** The datetime this entity was last modified. Automatically set by a JPA preUpdate */
#NoBinding
#Column
#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
public DateTime modifiedAt;
//...
}
#MappedSuperclass
public class Model extends GenericModel { // Both Model and GenericModel are from the Play Framework
#Id
#GeneratedValue
public Long id;
public Model() {
}
public Long getId() {
return this.id;
}
public Object _key() {
return this.getId();
}
}
jOOQ doesn't support all the many JPA and Hibernate specific annotations. Historically, it supported a few JPA annotations (because why not), but full interop would be excessive and investing product development time in the wrong places. jOOQ is by no means a JPA implementation.
Step 0: Why didn't (some) of the mappings work?
As mentioned before, not all JPA specification is implemented. For example, a known issue is that #Column annotations are still mandatory in jOOQ:
https://github.com/jOOQ/jOOQ/issues/4586
There might be other such limitations, which could be considered bugs. Feel free to report them if you want to continue down this path: https://github.com/jOOQ/jOOQ/issues/new/choose
But things like #MappedSuperclass or #Type are unlikely to ever be supported by jOOQ.
Step 1: Do you really need it?
You've decided to create and run your query with jOOQ. I imagine your actual query is much more complex than what you're showing, because for that particular query, you don't need jOOQ.
Do you really need to map to Hibernate entities? Because even when you use Hibernate, the recommended approach is to use entities only when you're going to modify them and store the delta back to the database. If that's the case, see step 2 below. If it's not the case, why not use jOOQ's own mapping functionality to work with any style of jOOQ supported POJO?
Step 2: Use Hibernate to execute the jOOQ query
If you're using jOOQ only to build a rather complex SQL query and you need Hibernate entities as a result, then use Hibernate to execute the jOOQ query as documented here. A small utility should be enough:
public static <E> List<E> nativeQuery(EntityManager em, org.jooq.Query query, Class<E> type) {
Query result = em.createNativeQuery(query.getSQL(), type);
List<Object> values = query.getBindValues();
for (int i = 0; i < values.size(); i++)
result.setParameter(i + 1, values.get(i));
return result.getResultList();
}

How to use a java class as a entity and also as a model

I have a entity class "classA" and a model class "ClassA1". ClassA is used to store the values in mysql database from server side and ClassA1 is used to convert a API response string into object which is client side.
Now I am having two java classes with same getters and setters but ClassA contains hibernate annotations and ClassA1 is simply a POJO. Consider the following class structures
ClassA.java
#Entity
#Table(name="classA")
public class ClassA {
#Id
private int id;
private String name;
public int getId() {
return id
}
public void setId(int id) {
this.id = id;
}
#Column(name="name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
ClassA1.java
public class ClassA1 {
private int id;
private String name;
public int getId() {
return id
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
My application is containg more number of classes like the above. I want to avoid this, because If I add any column to my database, currently I am adding getters and setters in both ClassA and also in ClassA1.
Is there any way to use a single class for both server and client side modules?
You can simply try to use same class in both situation. It should work. That's the way I tried in the beginning of one of my earlier project. As long as you can carefully deal with JPA merging of the ClassA you received from client-side by treating that as a detached entity.
However, when your entity design becoming more complicated, you will face a lot of problem (and that's why I switch away from this approach in my project :P). One of the biggest problem is, given you have modelled the entity relationships, once you try to "serialize" it for client use, a lot of (JAXB etc, at that time I was doing the projects) solution is going to recursively trace through all the relationship and try to convert it. Such behavior will trigger massive lazy fetching of entities, and make the result serialized form contains huge amount of (unused) data. Although you can control the behavior (by adding some kind of ignore annotation etc), the result entity will become messy to maintain.
Therefore what you are doing, imho, is not unreasonable. What you need to beware is, treat the value object (what you called "Model") something for "presentation". You don't need to make it strictly the same as your entities.
Make use of / develop some util library to handle the construction of value object from entities, and populating data from value object back to entities.
Of course, the suggestion may not apply to you, given that you haven't share much on your architecture.
You could specify your Hibernate mappings separately in an XML file instead of using annotations. This is the old way of doing it, nowadays most people use the annotations because it is more convenient and follows the JPA standard (mostly).
Another solution is to use a bean mapping framework like Dozer to make the mapping easier.
It's quite common to separate your persistent (JPA) Entities and value objects used by views in your architecture. You can customize the value objects for the view in which they are used. Maybe the view does not need the full User entity, but only the id, name and address? If this is the case it makes the communication between view and backend lighter and partially resolves the duplication between your ValueObjects and persistent entities.

Persisting third-party classes with no ID's

Say I have the following Java class, which is owned by a vendor so I can't change it:
public class Entry {
private String user;
private String city;
// ...
// About 10 other fields
// ...
// Getters, setters, etc.
}
I would like to persist it to a table, using JPA 2.0 (OpenJPA implementation). I cannot annotate this class (as it is not mine), so I'm using orm.xml to do that.
I'm creating a table containing a column per field, plus another column called ID. Then, I'm creating a sequence for it.
My question is: is it at all possible to tell JPA that the ID that I would like to use for this entity doesn't even exist as a member attribute in the Entry class? How do I go about creating a JPA entity that will allow me to persist instances of this class?
EDIT
I am aware of the strategy of extending the class and adding an ID property it. However, I'm looking for a solution that doesn't involve extending this class, because I need this solution to also be applicable for the case when it's not only one class that I have to persist, but a collection of interlinked classes - none of which has any ID property. In such a scenario, extending doesn't work out.
Eventually, I ended up doing the following:
public class EntryWrapper {
#Id
private long id;
#Embedded
private Entry entry;
}
So, I am indeed wrapping the entity but differently from the way that had been suggested. As the Entry class is vendor-provided, I did all its ORM work in an orm.xml file. When persisting, I persist EntryWrapper.
I don't have much experience with JPA, but I wouldn't extend your base classes, instead I would wrap them:
public class PersistMe<T> {
#Id
private long id;
private T objToWrap;
public(T objToWrap) {
this.objToWrap = objToWrap;
}
}
I can't test it, if it doesn't work let me know so I can delete the answer.

Avoid having JPA to automatically persist objects

Is there any way to avoid having JPA to automatically persist objects?
I need to use a third party API and I have to pull/push from data from/to it. I've got a class responsible to interface the API and I have a method like this:
public User pullUser(int userId) {
Map<String,String> userData = getUserDataFromApi(userId);
return new UserJpa(userId, userData.get("name"));
}
Where the UserJpa class looks like:
#Entity
#Table
public class UserJpa implements User
{
#Id
#Column(name = "id", nullable = false)
private int id;
#Column(name = "name", nullable = false, length = 20)
private String name;
public UserJpa() {
}
public UserJpa(int id, String name) {
this.id = id;
this.name = name;
}
}
When I call the method (e.g. pullUser(1)), the returned user is automatically stored in the database. I don't want this to happen, is there a solution to avoid it? I know a solution could be to create a new class implementing User and return an instance of this class in the pullUser() method, is this a good practice?
Thank you.
Newly create instance of UserJpa is not persisted in pullUser. I assume also that there is not some odd implementation in getUserDataFromApi actually persisting something for same id.
In your case entity manager knows nothing about new instance of UserJPA. Generally entities are persisted via merge/persist calls or as a result of cascaded merge/persist operation. Check for these elsewhere in code base.
The only way in which a new entity gets persisted in JPA is by explicitly calling the EntityManager's persist() or merge() methods. Look in your code for calls to either one of them, that's the point where the persist operation is occurring, and refactor the code to perform the persistence elsewhere.
Generally JPA Objects are managed objects, these objects reflect their changes into the database when the transaction completes and before on a first level cache, obviously these objects need to become managed on the first place.
I really think that a best practice is to use a DTO object to handle the data transfering and then use the entity just for persistence purposes, that way it would be more cohesive and lower coupling, this is no objects with their nose where it shouldnt.
Hope it helps.

how to insert/retrieve a userDefined Object in DB-MySql?

I want to insert and retrieve a a user defined Object in DB,am using Mysql5.1.
1)What should me the data type for the column(is Blob is the correct answer for this question)
I am using EntityClass to Insert/Get values from the DB.
2)but to how to insert Object in database?
The common way is to translate the object to a table - every field of the object is (toughly) translates to a column of the table. The term for this is object relational mapping. There is plenty of documentation of this on the web (like this) as this is one of the cornerstones of modern day enterprise development.
There are several libraries you can use, and the best is to stick to the standard called JPA - Java Persistence API. The most known libraries (all open source) are
Hibernate
EclipseLink
OpenJPA
Your user defined object will look like this :
#Entity
#Table(name = "some_table")
public class SomeObject implements Serializable {
static final long serialVersionUID = <some value>;
#Id
#GeneratedValue
protected Long id;
#Column
protected String name;
#Column
protected int value;
// default constructor
// getters, setters
// equals, hashCode, toString
// other methods
}

Categories

Resources