JPA and unique fields - java

I have two persistence objects in my app: Things and tags attached to things. The app can generate collections of things with tags attached. Tag objects have a unique name (it doesn't make sense to tag something twice with the same tag).
When inserting a Thing (with tag objects attached) some of these tag objects with the same name maybe already exist in the db. Now here is the part I don't recall about JPA, is there a way to tell JPA that it should not try to add the corresponding objects to the db if it violates the unique constraint? Or is there a way to do this efficiently w/o having to first fetch all objects, then merge the collection in memory and then write everything back?
I'm also wondering if it's possible to persist a whole collection at once or do I have to call persist for every object when using JPA?

I don't know of any way of doing this 'cleanly', neither with JPA nor with Hibernate or any other provider. You can achieve what you want with a custom SQL query though (similar to this question):
#Entity
#Table(name="tag")
#SQLInsert( sql="INSERT INTO tag(name, count) VALUES (?, ?)
ON DUPLICATE KEY UPDATE set count = count + 1")
public class Tag {}
Now you are unfortunately bound to both Hibernate and MySQL. You can vary the sql syntax for other DB:s, and/or use stored procedures, try an update first and insert on failure etc. They all have their drawbacks, so it would be handy if JPA would support this, but alas.
Regarding you second question, JPA support persisting whole object graphs, including collections.

Related

How to properly update entities using REST and JPA/Hibernate

I have entity Document, which has lots of columns, one-to-one, one-to-many and many-to-many mappings to some other entities.
Example:
Document:
id,
title,
body,
authors,
viewers,
...
Using REST, I want to update some particular document, controller receives serialized Document object, calling EntityManager's merge method persists null results to the database if controller received for instance only body , then I want the body to be updated only, but merge deletes records for title, authors and viewers and etc.
I understand that it is a standard behavior of EntityManager, but I am asking what is the most preferred technique to do updates on entities without receiving whole entity from front-end or some other endpoint. Should I load the entity from database using the id I received and set MANUALLY all of the fields and then save to database or should I use another technique.
I don't have any problem with writing manually all of the setters to copy the changes, but entities are really big in size with lots of relations. Asking for best practice in this case.
I know about DTOs but I want alternate approach when using entities for controllers and service methods.
For entity partial update, you will need to use either criteria api or jpql ... if you are using older versions with no criteria update or old query parser where jpql update is not allowed you will have to read from database first, update then insert again .... you can also make use of updatable=false for columns that should be only set on creation (like CREATION_DATE) and there is also a nice feature in hibernate called #DynamicUpdate which I haven't tried but looks brilliant ... It only updates the modified field (check Vlad's post here) ... concerning the DTO DP , I you might always need to use if you want to hide / modify some data from the client regardless to the way you store the data ... and it's always a good way to separate concerns (but comes with the mapping headache between domain & DTO objects which is much released thanks to spring converters)
There are two options one is update query, which works fine but you may feel
you are loosing some hibernate features and simplicity of the code. Else you can do it in Hibernate way like below
AuditorBean auditorBean = (AuditorBean) session.get(AuditorBean.class, AuditorBean.getId());
auditorBean.setFirstName("aa");
auditorBean.setLatName("bb");
auditorBean.setTrainLevel("ISO");
auditorBean.setAccessLevel(4);
Here you should not call any method like saveOrUpdate() or merge().
object is attached with transaction, so object is flushed and committed at the end of the transaction automatically .

How to alter databases tables at run time using JPA?

I am creating CRUD application for customer . and he asked me to allow him to create new Fields in a form (database columns) without restarting the application server. which JPA implementation should I use (hibernate , eclipselink ,openjpa)
to accomplish this task and how it will be done?
Please don't change the database schema at runtime.
Assuming, you would add a column to a table. Then you have to add a field in your entity class, too. And the mapping. So you not only have to change a Java class at runtime, at next application start, you must add this field again. No JPA implementation can do that.
Of course, you can use plain JDBC. And instead of entity classes with concrete fields you can use something like a map for your dynamic fields. But you should adapt all your SQL queries according to the presence of dynamic fields. So you need a way to store the information, which dynamic fields are already created. You can do this with another table or use the table meta information. Additionally you have to manage user defined field names. E.g you should avoid SQL keywords, there is a maximum field name length, etc.
Or you can step back and rethink your approach. You have a requirement: Static given fields in a form and the possibility to create dynamic fields.
Why not adapt your data model to that requirement? A data model which is able to handle dynamic form fields. Such flexible datamodel wouldn't need dynamic SQL table field creation. (And JPA can handle that, too.)
The simplest example would be a table with two columns. One for the field name and one for the value (as string). Maybe a third one to identify the type.
Another alternative would be to use a NoSQL database system like a key value store or a document oriented database.

Linking entities to existing tables without code

Let's assume that we have java entities already implemented and annotated with Jpa annotations.
We also have an existing database slightly different to the schema described by said entities.
How I can link the data base with my entities without the code?
Otherwise, how can i proceed from the begining when implementing my entities to make this stuff configurable ( give the user the possiblity of specifying the names of the columns corresponding to the fields of each entity in an externalized configuration file)?
NB: I use hibernate as an ORM.
I believe this is what you are looking for

Do I need entities if only getting data from db?

Hopefully easy questions:
If I have an application that is supposed to only get data from
database (it doesn't persist anything)?
Do I need an exact structure of db presented by set of
#Entity-annotated classes?
Do I need Entities at all anyway?
Or can I just use DAO and do something like:
ObjectFromDb ob = dao.find(someProperty);
given that ObjectFromDb is just a regular POJO without a single JPA
annotation?
I google'd it for a short while, but it seems to be too specific questions... Thanks for any advice!
You do not need entities for querying, but they can make your life easier.
You can use regular SQL for queries.
You can also have some entities defined, but query only for a subset of their data - i.e. a projection query.
You can also use JPA constructor command with projection queries to map directly to your result objects:
List<MyClass> dtos = em.createQuery("SELECT NEW com.example.MyClass( e.name, e.data) FROM Entity e").resultList();
EDIT: With annotated entities you can use features of JPQL that are not available in SQL, e.g. path navigation. Properly annotated entities can clarify the DB mapping.
An entity does not need to map all columns of a table, you can use any subset you like, as long as it includes the id.

Hibernate and stored procedures

As my understanding on setting hibernate, I need to create
table meta data file (person.hbm.xml), include all the fields mapping
java object (person.java)
If we use stored procedures for all transaction, do we still need the above configuration?
It seems hibernate and stored procedures will overlap,
We set up the stored procedure because we don't want the to developer know all the field in db. If tables change, then we need update above files.
Does it mean if we purely use stored procedure, we should just go for JDBC?
If hibernate, we should stay in HQL?
You can use native SQL and map the result to object:
sess.createSQLQuery("SELECT * FROM CATS").addEntity(Cat.class);
The JDBC syntax to invoke store procedure is like following:
CallableStatement proc =
connection.prepareCall("{ call set_death_age(?, ?) }");
proc.setString(1, poetName);
proc.setInt(2, age);
So maybe, you can invoke stored procedure and map them to object:
sess.createSQLQuery("{ call my_stored_proc }").addEntity(Cat.class);
Note also that updates made through stored procedures will escape hibernate, which means that you will need to evict objects from the 1st level and 2nd level cache yourself.
So as you see, hibernate and stored procedure don't really fit naturally together.
we set up the stored procedure because
we don't want the to developer know
all the field in db. if table change,
then we need update above files.
If you're concerned about security, either use:
database views
Oracle column priviledges
provide mapping files and forbid their modification by developpers
Using Hibenate with Stored Procedures is a certain overlap. As you for example need to write astored procedure for INSERT, UPDATE, DELETE and SELECT, Hibernate provides an easiest way to interract with with relational database objects by mappings them into metadata files like you mentioned person.hbm.xml.
Yes, the use of stored procedure wil require you to write these metadata files anyway. A stored procedure will not replace the Hibernate mappings. Those mapping only tell Hibernate how to persist your object-oriented model to the database. A great thing about Hibernate is that you may even, if needed, generate you database model from your JAVA code through the schema generation tool.
As for the stored procedures, one recommended way is to configure your stored procedures as named queries from within the configuration file. This, however, makes you miss the better potential, in my opinion, of Hibernate.
Does this answer your question? Do you need further explanations?
It is possible to use native-sql and to use stored procedure for querying (with limiations/rules). But, as written in the documentation:
Stored procedures currently only return scalars and entities. <return-join> and <load-collection> are not supported.
So if you want to work with non-managed entities (i.e. not scalars in an Object[]), you'll have to apply a ResultTransformer in the code.
But at the end, if you want to hide the database to developers, if you don't want to map objects to tables, if you don't want to work with associations, if you don't want to use HQL, if you don't want to use an OO approach, then I really wonder why you want to use Hibernate. You'd better use raw JDBC (with Spring for example) or maybe a data-mapper like iBATIS.
You can map the database fields in a result set to an object in hibernate: the documentation explains how.
The idea of Hibernate is to fill the object-relational gap. With the stored procedures (which I can't guess since you haven't told anything about them) you can't get objects from database. You still get rows.
Hiding the database columns from developers sounds like a bad practice to me. Hiding them from the application is perhaps what you want, and you achieve that with the metadata file.

Categories