How does JPA EntityManager determines if an entity already exists? - java

Suppose I have EntityManager em and that I have Entity e. When I call em.persist(e) the Java EE JPA documentation says that an EntityExistsException is thrown if e already exists in the persistence context.
Now, suppose that entities of type Entity have a surrogate key generated automatically by the database, but they also have a field (or fields) with uniqueness constraints that make any entity of type Entity unique.
How does EntityManager em determines that the new element I am trying to insert to the database already exists there? Is it from the equals method defined in Entity, or is it by attempting to insert to the database and getting back an error because some uniqueness constraints were violated? (Obviously, I think it shouldn't be because the surrogate primary key of the object I am inserting is equal to the surrogate primary key of an object in the database, since the surrogate primary key of the object I am inserting is null (or my thinking is wrong here?)). If it is the latter, how am I sure that the persist is throwing an EntityExistsException instead of a PersistenceException?

There is no other way than doing an INSERT and catching a database exception. Any other ways are unreliable since databases are multi-user environments.
For example, oracle throws a "unique constraint violated" and it shows which
constraints were violated.
QL Error: ORA-00001: unique constraint (SCHEMA_NAME.CONSTRAINT_NAME) violated

Related

Repetition of constraint in liquidbase and entity definition

I`ve noticed that in my project some composite constraint are set in a liquidbase,
for example
constraint importer_ukey unique (name, country_id, is_importer, is_manufacturer)
but then they are repeated in entity definition in #Table annotation
#Table(uniqueConstraints = {#UniqueConstraint(name = "importer_ukey",
columnNames = {"name", "country_id", "is_importer", "is_manufacturer"})})
Is there any positive in repetition of uniqueConstraint in entity ?
Other than for creating the schema based on the JPA annotations, it is also a needed at runtime for the JPA provider to order INSERT, UPDATE and DELETE statements correctly.
Unique constraints ensure that the data in a column or combination of columns is unique for each row. A table's primary key, for example, functions as an implicit unique constraint. In JPA, you represent other unique constraints with an array of UniqueConstraint annotations within the table annotation. The unique constraints you define are used during table creation to generate the proper database constraints, and may also be used at runtime to order INSERT, UPDATE , and DELETE statements. For example, suppose there is a unique constraint on the columns of field F. In the same transaction, you remove an object A and persist a new object B, both with the same F value. The JPA runtime must ensure that the SQL deleting A is sent to the database before the SQL inserting B to avoid a unique constraint violation.
Source: https://openjpa.apache.org/builds/1.0.2/apache-openjpa-1.0.2/docs/manual/jpa_overview_mapping_unq.html
So yes: it is important.

Persistent entity '*******' should have primary key error in #Entity class

When creating an #Entity mapping a table my IDE notifies me: Persistent entity '*******' should have primary key.
But the table in the DB doesn't have an ID (I think it's bad but it's legacy which I've no permissions to fix)
What should I do? Will it work if I just omit the ID field? Or should I make up an ID which is not mapped on the table but satisfy the code?
Every JPA entity must have a primary key.
You can find the documentation here.
From the Java Persistence book: Identity and Sequencing: here
If your object does not have an id, but its table does, this is fine.
Make the object an Embeddable object, embeddable objects do not have
ids. You will need a Entity that contains this Embeddable to persist
and query it.
Try also to read the answers here

In Hibernate/JPA how to tell if the ConstraintViolationException is a PK, a FK, or a unique key violation?

I am developing a generic method with generic handling to persist an entity in the database, however I am having difficulty in knowing if the ConstraintViolationException is a violation of primary key, foreign key or unique key
public Collection<T> salvar(final Collection<T> e) {
try {
return dao.salvar(e);
} catch (ConstraintViolationException e1) {
if (PK_violation) {
handle PK error
} else if (FK_violation) {
handle FK error
}
}
}
How do I know what type of violation is my exception (PK_violation or FK_violation)?
Thanks
You will need to parse the exception message to extract the name of the key that triggered the exception. Once you have the index name in hand, you will have to be able to recognize which type of index it is based on naming conventions or based on metadata about your database schema.
Here are a couple of examples from some logs I have handy:
Duplicate entry '1023' for key 'PRIMARY'
Duplicate entry 'test-user-817fe6b0-587a-4003-9dec-8d2ea8f87cad' for key 'UKwqsqlvajcne4rlyosglqglhk'
The first case is a primary key violation - "PRIMARY" seems to be the key name that shows up in this case. The second is a unique key violation - in our case, our unique key names start with "UK" so we can use this to determine it was that type of index that was violated.
So, apply a regular expression to e1.getMessage() with a group for the key name, extract that group value, apply another regular expression or other business logic to determine which kind of index you are dealing with based on your local naming conventions or by querying the database for information about the index.
You can query the database for information about the nature of the index that is mentioned in the exception. If you are going to use a database query, you could do a single query at startup to gather metadata about all indexes and use this cached data for the rest of the run.
If you are using annotated Java classes to specify the JPA mapping, you could utilize those annotations (perhaps with an annotation processor or at runtime via reflection) to extract the information about the indexes. In particular, the javax.persistence.Id annotation results in a primary key and javax.persistence.Table has a uniqueConstraints attribute that utilizes javax.persistence.UniqueConstraint to define the unique constraints. Trying to do this at the time of the exception handling would be difficult, because you probably cannot figure out which entity object triggered the violation - in the general case, there are many entities being flushed to the database at the same time; I am unaware of a way to determine which one triggered the problem.
I am unaware of any JPA API that will allow you to extract this information from the EntityManager or persistence unit.

Does a JPA persist() operation always include all the mapped entity fields in the generated INSERT statement?

My question is related to Is there a way to prevent null values from being persisted while allowing others through? and Is it necessary to set all the fields of the entity classes when using JPA to persist?, but goes in the opposite direction.
Instead of preventing null values from being persisted, I would like to be sure that null values are consistently used in the generated INSERT INTO statement of a persist operation so that I can detect NOT NULL constraint violations in my application code.
The reason is because my team has a convention on the underlying database (Postgres) that demands that every NOT NULL column also uses a DEFAULT value, which is needed for an automatic migration script we're using.
Due to the problems described in the first linked thread, I want to assure that my JPA (EclipseLink) cache does not get out of sync with the DB due to default values automatically being used upon an INSERT INTO. This could happen if the INSERT INTO completely omits a column - in that case the defined DEFAULT value would be used by the DB to fill the row.
I've observed that EclipseLink always seems to use all the mapped columns in the INSERT INTO statement, explicitly setting null values. This triggers the constraint violation as desired.
But is this guaranteed to happen or could the JPA provider decide to completely omit a column in the INSERT INTO statement that is mapped to a Java field containing a null value (leaving insertable = false annotations aside)?

No identifier specified for entity in java hibernate

I am using hibernate and i mapped my table with my bean. If i am not assign any particular column value as #id, it throws "No identifier specified for entity" error, however it is not primary key in my data table. I want to add multiple records with same data. how can i do it? When i annotated my product Name column with #id my code runs perfect.
Hibernate requires an identifier for each entity. However, it is possible to use native queries to insert new records. And, in the same way, to recover them.

Categories