JPA and PostgreSQL with GenerationType.IDENTITY - postgresql

I have a question about Postgres and GenerationType.Identity vs Sequence
In this example...
#Id
#SequenceGenerator(name="mytable_id_seq",
sequenceName="mytable_id_seq",
allocationSize=1)
#GeneratedValue(strategy = GenerationType.SEQUENCE,
generator="mytable_id_seq")
I understand that I am specifying a Postgres sequence to use via annotations.
However, I have an id column defined with the 'serial' type, I have read that I can simply use GenerationType.IDENTITY and it will automatically generate a db sequence and use it to auto increment.
If that's the case, I don't see an advantage to using the SEQUENCE annotations unless you are using an integer for an id or have some specific reason to use another sequence you have created. IDENTITY is alot less code and potentially makes it portable across databases.
Is there something I'm missing?
Thanks in advance for the feedback.

If you have a column of type SERIAL, it will be sufficient to annotate your id field with:
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
This is telling Hibernate that the database will be looking after the generation of the id column. How the database implements the auto-generation is vendor specific and can be considered "transparent" to Hibernate. Hibernate just needs to know that after the row is inserted, there will be an id value for that row that it can retrieve somehow.
If using GenerationType.SEQUENCE, you are telling Hibernate that the database is not automatically populating the id column. Instead, it is Hibernate's responsibility to get the next sequence value from the specified sequence and use that as the id value when inserting the row. So Hibernate is generating and inserting the id.
In the case of Postgres, it happens that defining a SERIAL column is implemented by creating a sequence and using it as a default column value. But it is the database that is populating the id field so using GenerationType.IDENTITY tells Hibernate that the database is handling id generation.
These references may help:
http://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#identifiers-generators
https://www.postgresql.org/docs/8.1/static/datatype.html#DATATYPE-SERIAL

From "Pro JPA2" book:
"Another difference, hinted at earlier, between using IDENTITY and other id generation strategies is that the identifier will not be accessible until after the insert has occurred. Although no guarantee is made about the accessibility of the identifier before the transaction has completed, it is at least possible for other types of generation to eagerly allocate the identifier. But when using identity, it is the action of inserting that causes the identifier to be generated. It would be impossible for the identifier to be available before the entity is inserted into the database, and because insertion of entities is most often deferred until commit time, the identifier would not be available until after the transaction has been committed."

I think it can be helpful if you are using the same sequence for more than one table (for example you want a unique identifier for many types of bills) ... also If you want to keep track of the sequence away from the auto generated key

You can find here the solution of updating the PostgreSQL table creation accordingly, in order to work with the GenerationType.IDENTITY option.

Related

Spring Data JPA bulk identifier generation

I have an entity, for which apart from the primary key, an extra unique identifier should be generated:
#Entity
class MyEntity(
val otherId: String // <- this id is unique as well
) {
#Id
#Generated
var id: UUID // PK
}
otherId property value is derived from a postgres sequence value, by calling SELECT nextval(...) and adding a prefix string. When I do bulk inserts, I have to resort to a custom query defined in my JPA repository for the entity, which retrieves multiple sequence values at once, but I'd like to make this process automatic.
I tried to implement IdentifierGenerator interface, but the best I could achieve is a single SELECT nextval query was made for each new entity inserted, which is totally unacceptable in my case since batches can consist of hundreds of entities. Digging into the hibernate details didn't give me an answer how to do that either.
Is there a way to generate a number of ids via some callback/hook for multiple entities at once? Or I still have to do everything by hand?
There are hooks to implement this, see this article as an example: https://thorben-janssen.com/custom-sequence-based-idgenerator/
To improve performance, you will have to configure the increment size, which by default is 50. This means that it will increment the sequence by 50 and put these values in a pool from which the values are served for identity generation.

How to create relationships between entities with existing database that does not contain foreign keys

Using Entity Framework Core 2.0
Stuck with company's production database which has primary keys defined for each table but no foreign keys defined for any relationships.
Dependent records in the database have id fields which are intended to relate to the primary key fields of the parent record like you would normally find with a foreign key relationship/constraint. But these fields were all created as INT NOT NULL and are using a SQL default of '0'.
As a result dependent records have been inserted over time without requiring that a related parent record be specified.
Initially I defined my models in EF with integers and used a fluent configuration to specify "IsRequired". This was done so I could run migrations to create a test database for comparison against the production database to verify that my code first was correctly coded.
This then lead to the problem while using "Include" in my Linq queries which performs an inner join that results in dropping the records that contain the 0's in the id fields of the dependent record.
The only way that I have found to make this work is to model all of the id fields in the dependent entity as nullable integers and remove the "IsRequired" from the fluent configuration.
When using the "Include" it performs a left outer join keeping all of the dependent entities. This also means that any reference properties on the included entities are set to null instead of an empty string. This part can probably be fixed fairly easily.
The downside is if I wanted to use migrations to create a database now, all id fields in the dependent records would be created as NULL.
Is there anyone who has run up against this type of situation? Does anyone have any suggestions to try other than the approach I am using?
I haven't dealt with this scenario before but I wonder if you can solve it by defining the FK property as Nullable and then in the migrations, after the migration is created, edit it to add a HasDefaultValue property to ensure that it's 0? (doc for that migration method: https://learn.microsoft.com/en-us/ef/core/modeling/relational/default-values)

Generate Hibernate Envers primary key manually and jpa as well

My project is migrating from Grails to Java so I have exisiting Audit data in a single table pushed by Grails Audit plugin, now I am using Java envers for Auditing in java. I have below doubts:
-> If i want to push data from single table to different Audit tables(in Java) manually, how can i generate Primary key of revision table for history data manually which will not collide with primary key generated from Java annotation?
As for new entries I am generating primary key like below:
#Id
#GeneratedValue
#RevisionNumber
#Column(name = "ID") #NotNull
private Long revisionId;
-> Any other way to push data from single audit table to segregated Audit tables(In java) instead of doing it manually?
Please let me know about this.
Thanks.
Envers should be creating sequence named REVISION_LISTENER on Oracle.
Therefore you should be able to use Oracle's syntax SELECT REVISION_LISTENER.NEXTVAL in order to get the next sequence value and use that in the REV field both in your audit table and the revision entity info table too.
This only applies to DefaultAuditStrategy.
If you intend to use the ValidityAuditStrategy, there are other fields which you'll have to understand the internals of Envers in order to be able to populate the relevant fields. If you are using this strategy, let me know and I'll add more details that are specific to it, but its very complex and quite tedious.

Postgresql: How #GeneratedValue works in postgresql?

I am very new to postgresql. In playframework with Ebean, I have used mysql and auto generated value there was actually auto incremented in that case. The sequence I got was 1,2,3,4...
But in Postgresql, the generated value doesn't seem to have such property. It seems that for every session it is starting with a number larger that the previous session's number and then auto incremented. The sequence in this case, 1,21,41,42,61,81,101,102,103...
My code segment:
#Entity
public class Post extends Model{
#Id
#GeneratedValue
#Required
public int id;
I am using:
Playframework 2.3.4
Ebean
Postgres 9.3
I really don't know the reason. Is there any particular reason of such values? Is there any catch about this? Do I need to switch to auto increment? And if so, how do I do it?
K, so you're using AUTO strategy, as it's the default. I don't know much about Ebean, but with Hibernate, a sequence called hibernate_sequence is created.
This sequence would be shared by other entities, so that might be part of the reason for the gaps. Your ORM might also be pre-allocating sequence values for performance reasons.
Either way, I always use IDENTITY strategy with Postgres, even though Postgres doesn't use IDENTITY. It does however create a sequence per table, which is generally what you want.

JPA SequenceGenerator and GeneratedValue: name / generator property unique only per class?

I use JPA + OpenJPA with PostgreSQL as backend RDBMS. The primary keys of my tables usually consist of a SERIAL / BIGSERIAL column. So PostgreSQL automatically generates IDs for new entries (strategy=GenerationType.IDENTITY).
The annotations of ID property look like this:
#Id
#SequenceGenerator(name="myseq",sequenceName="foobartable_fooid_seq")
#GeneratedValue(generator="myseq",strategy=GenerationType.IDENTITY)
My question is: Can I copy and paste this annotations block to several entities, while only modifying the sequenceName value? The sequenceName is different from table to table. But may the SequenceGenerator of all Entities be named myseq or something like that? Or does one have to specify a unique generator name for the SequenceGenerator of each Entity? So that each SequenceGenerator name must be unique in the persistence unit?
Is it possibly a good idea to use the same value used for the sequenceName in the database? So that I'd write something like
#Id
#SequenceGenerator(name="foobartable_fooid_seq",sequenceName="foobartable_fooid_seq")
#GeneratedValue(generator="foobartable_fooid_seq",strategy=GenerationType.IDENTITY)
Any recommendations on how to name the SequenceGenerators?
Many thanks in advance for any suggestions!
Yours,
Mr. Snrub
From the Javadoc for SequenceGenerator, emphasis is mine:
Defines a primary key generator that may be referenced by name when a
generator element is specified for the GeneratedValue annotation. A
sequence generator may be specified on the entity class or on the
primary key field or property. The scope of the generator name is
global to the persistence unit (across all generator types).
So you will want to use a unique name for each sequence defined in a persistence unit. On a tangent, your GeneratedValue strategy should be SEQUENCE, as pointed out in a comment above.