Spring JPA sequence generator initial value is not working - spring

I have one entity that already have records in database (20 records).
My primary key column is already defined as SERIAL in a postgres database.
My entity:
#Entity
#Table(name = "foo", schema = "public")
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class FooEntity {
#Id
#SequenceGenerator(name="foo_seq", sequenceName = "foo_seq", initialValue = 20, allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "foo_seq")
#Column(name = "id")
private Integer id;
}
I run a query that returns all existing sequences in database and i find the "foo_seq".
In my service, when i try to call my repository to save the data, its returned this error:
FooEntity fooEntity = FooEntity.builder()
.id(null)
.build();
FooEntity savedEntity = fooRepository.save(fooEntity);
Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key
value violates unique constraint "foo_pkey" Detail: Key (id)=(5)
already exists.
Seems that spring is not using the value defined in initialValue (should try to save with id 20, but instead, is using your own increment starting with 1). When i call this method again, the increment is added, but not starting with 20.
I'm missing something? Should i have alter this sequence in postgres to start with id 20?

Related

Spring MapsId not resolving target entity

I have such a case where I need to have internally many-to-one using hibernate proxies and only id externally, here using MapsId. The issue appears when I try to save something, because the target entity is not fetched, when I set the value only on the id.
Let's take an example: I have an Account table and DeviceConfig table. Inside the DeviceConfig's class definition, I add account in a many-to-one relation and accountId in relation with #MapsId.
Now when creating, I always set a value to accountId, but never the value is picked up, and the backend throws an SQL error, because the field cannot be null.
#Table(name = "djl_device_config")
#Entity
#Getter
#Setter
#ToString
#RequiredArgsConstructor
public class DeviceConfig extends CoreEntity {
...
#JsonIgnore
#ManyToOne
#MapsId("accountId")
#JoinColumn(name = "account_id")
private Account account;
#Column(name = "account_id", insertable = false, updatable = true, nullable = true)
private UUID accountId;
}
So I suppose this is a config error on my side, but I've been reading the JPA for these three days and I still don't know what's wrong or what I should do to achieve the behaviour I expect.
That for any help you'll provide.

Spring Data + View with Union return duplicate rows

i'm using Spring Boot 2.4.2 and Data module for JPA implementation.
Now, i'm using an Oracle View, mapped by this JPA Entity:
#Entity
#Immutable
#Table(name = "ORDER_EXPORT_V")
#ToString
#Data
#NoArgsConstructor
#EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class OrderExportView implements Serializable {
private static final long serialVersionUID = -4417678438840201704L;
#Id
#Column(name = "ID", nullable = false)
#EqualsAndHashCode.Include
private Long id;
....
The view uses an UNION which allows me to obtain two different attributes of the same parent entity, so for one same parent entity (A) with this UNION I get the attribute B in row 1 and attribute C in row 2: this means that the rows will be different from each other.
If I run the query with an Oracle client, I get the result set I expect: same parent entity with 2 different rows containing the different attributes.
Now the issue: when I run the query with Spring Data (JPA), I get the wrong result set: two lines but duplicate.
In debug, I check the query that perform Spring Data and it's correct; if I run the same query, the result set is correct, but from Java/Spring Data not. Why??
Thanks for your support!
I got it! I was wrong in the ID field.
The two rows have the same parent id, which is not good for JPA, which instead expects a unique value for each line.
So, now I introduced a UUID field into the view:
sys_guid() AS uuid
and in JPA Entity:
#Id
#Column(name = "UUID", nullable = false)
#EqualsAndHashCode.Include
private UUID uuid;
#Column(name = "ID")
private Long id;
and now everything works fine, as the new field has a unique value for each row.

Hibernate generated id cause error message : "key already exists"

I'm using spring app with hibernate and postgres to store data. The configuration for the product entity is as follow :
/**
* A Product.
*/
#Entity
#Table(name = "product")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#Document(indexName = "product")
public class Product implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
...
}
When I want to create a product using the web app I get the following error duplicate key value violates unique constraint. Detail : the key (id)=(35018) already exists.
From my understanding hibernate use a sequence in db to generate the next id value. So I did SELECT c.relname FROM pg_class c WHERE c.relkind = 'S'; in the psql shell to get all sequence in my db. The output is :
hibernate_sequence
jhi_user_id_seq
key_value_id_seq
jhi_persistent_audit_event_event_id_seq
unit_id_seq
generic_user_id_seq
currency_id_seq
customer_type_id_seq
customer_exploitation_type_id_seq
legal_entity_id_seq
deposit_id_seq
machine_id_seq
tank_id_seq
address_id_seq
product_id_seq
rewarded_file_id_seq
bar_code_type_id_seq
quality_label_id_seq
shop_pdv_id_seq
brand_id_seq
category_id_seq
material_id_seq
ws_call_id_seq
postal_code_id_seq
commune_id_seq
country_id_seq
event_id_seq
event_type_id_seq
key_blob_id_seq
card_id_seq
So I thought nice I have a product_id_seq and I only have to update the value in it for things to work.
But when I request the value with SELECT * FROM product_id_seq; I get :
last_value | log_cnt | is_called
------------+---------+-----------
100616 | 0 | t
So here I think that the id generated for the product id is not coming from this product_id_sequence since it tries to insert a product with id = 35018 and the product_id_seq last value is 100616.
So I wonder where does this id 35018 comes from? Which sequence is used to generate it? My guess is I have to update this mysterious sequence to get things to work. For info the hibernate sequence has a value of 36400.
Any idea that could get me going? Thanks in advance.
You do not map your sequence with postgre sequence so Hibernate creates the sequence hibernate_sequence (the one you got 35018 from) for itself.
To use your existing sequence:
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator", sequenceName = "product_id_seq")
private Long id;

Hibernate Sequence Conflict after using Audited annotation

I'm using hibernate in my spring boot application
my domain model is like this
#Entity
#Table(name = "skill")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#Document(indexName = "skill")
#Audited
public class Skill implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
}
The increment size of sequence is 50 and is working properly
but when I add Envers Audited annotation I see this error
conflicting values for 'increment size'. Found [50] and [1]
How can I resolve this conflict?
This doesn't sound like an Envers problem but a general mapping problem.
When you add an #Audited annotation, that simply informs Envers that it should inspect that particular entity mapping during Hibernate bootstrap and create the necessary audit objects to store the entity state during each transaction.
The generated Envers objects use their own sequence generators and primary key. The user defined generation strategy, sequences, etc are all ignored in the Envers object because the associated column is meant to just be a copy/pass-thru value, nothing special.
In other words, the Envers table would have a PK defined that mirrors this POJO:
#Embeddable
public class EnversSkillId implements Serializable {
#Column(name = "REV", nullable = false, updatable = false)
private Integer rev;
#Column(name = "id", nullable = false, updatable = false)
private Long id;
}
When Envers generates the audit record, it automatically uses its internal sequence generator to get the next value and assign it to EnversSkillId#rev and copies your entity's id value directly into the EnversSkillId#id property.
So as mentioned in the comments, your problem is very unlikely related to Envers.

sequence does not exist exception using eclipseLink with oracle db

I've got the following JPA entity:
#Entity
#Table(schema = "myschema")
#SequenceGenerator(schema = "myschema", name = "seqGenerator",
sequenceName = "person_s1", allocationSize = 1)
public class Person {
#Id
#GeneratedValue(generator = "seqGenerator", strategy = GenerationType.AUTO)
private long id;
the following exceptions are thrown:
Call: DROP SEQUENCE myschema.person_s1
Query: DataModifyQuery(sql="DROP SEQUENCE myschema.person_s1")
[EL Warning]: 2010-11-01 17:21:51.051--ServerSession(10605044)--Exception [EclipseLink- 4002] (Eclipse Persistence Services - 2.1.1.v20100817-r8050):
org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: ORA-02289: sequence does not exist
Error Code: 2289
Call: SELECT myschema.person_s1.NEXTVAL FROM DUAL
Query: ValueReadQuery(sql="SELECT myschema.person_s1.NEXTVAL FROM DUAL")
The sequence is genrated by EclipseLink and the query:
SELECT myschema.person_s1.NEXTVAL FROM DUAL
works fine when used directly...
Any help appreciated
Regards Marcel
the following exceptions are thrown (...)
These traces are generated during schema creation when a particular database object doesn't exist and thus can't be dropped. EclipseLink report such cases as Warning (which are not Error), they can be ignored (you get your sequence, right?).
PS: Why do you use an allocation size of 1, don't you want to benefit from the high/low optimization?
I know this is going to sound really silly, but here it is anyway.
#Entity
#Table(schema = "myschema")
public class Person {
#Id
#SequenceGenerator(schema = "myschema", name = "seqGenerator", sequenceName = "person_s1", allocationSize = 1)
#GeneratedValue(generator = "seqGenerator", strategy = GenerationType.AUTO)
private Long id;
}

Resources