JPA Sequence Generated Value Not Working - java

I need to use an existing sequence of the db to generate the id of this entity:
#Entity
#Table(schema="sistema", name="clientes_consultas")
public class Consulta implements Serializable {
#Id
#SequenceGenerator(schema = "sistema", sequenceName = "clientes_consultas_id_seq",
name = "seq_c", allocationSize = 1, initialValue = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_c")
protected Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
This is my sequence, and its stored on a schema that is not the postgres default 'public', its called 'sistema':
Unfortunately, theres an stacktrace saying that the sequence dont exists :(
Any clue?

Your sequence owner is "postgres". Maybe you defined different user than postgres in your connection.

Related

Hibernate - Insert generated id in column other than id one on save

is there a way to perform insertion of an #Id-column value into a non #Id column when entity is being created/updated to avoid double-save-ing?
#Entity
class DummyEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "dummy_id_generator")
#SequenceGenerator(name = "dummy_id_generator", sequenceName = "dummy_id_seq")
Long id;
Long rootId;
}
#Repository
class DummyEntityRepo implements JpaRepository<DummyEntity, Long> {}
#Service
class DummyEntityService {
#Autowired
DummyEntityRepo repo;
void save(DummyEntityVO newDummyEntity) {
var newEntity = newDummyEntity.mapToEntity();
// !!! double save here !!!
repo.save(newEntity);
if(newEntity.getRootId() == null) {
newEntity.setRootId(newEntity.getId());
repo.save(newEntity);
}
}
}
What I was thinking was, since #Id is based on a sequence, I can try extracting next value from it and setting it as id and rootId before saving
Long nextId = // get next id somehow
newEntity.setId(newId);
if (newEntity.getRootId()) {
newEntity.setRootId(nextId);
}
repo.save(newEntity);
However:
I don't like perspective of interfering with Hibernate's id acquisition & saving methods
I found package org.springframework.jdbc.support.incrementer but unfortunately there is no sequence based OOB incrementer for my DB so it would require a custom implementation (found something promising here though)
#GeneratorType allows to generate/set values into entity during insertion phase. Suppose your entity looks like this:
#Entity
class DummyEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "dummy_id_generator")
#SequenceGenerator(name = "dummy_id_generator", sequenceName = "dummy_id_seq")
Long id;
#GeneratorType(type = RecordIdGenerator.class, when = GenerationTime.INSERT)
Long rootId;
}
And your RecordIdGenerator class looks like:
public class RecordIdGenerator implements ValueGenerator<Long> {
#Override
public Long generateValue(Session session, Object owner) {
return ((DummyEntity)owner).getId();
}
}
Then when you'll insert new record hibernate will generate similar queries:
Hibernate: select nextval ('dummy_id_seq')
Hibernate: insert into dummy (record_id, id) values (?, ?)
and record_id will be equal to id

JPA overwrite record with auto_increment primary key

I've searched but nothing found for me. I have an entity class like this belove:
#Entity
public class Report {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#Column(name = "descrizione")
private String descrizione = null;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getDescrizione() {
return descrizione;
}
public void setDescrizione(String descrizione) {
this.descrizione = descrizione;
}
}
And a table into mysql db with auto_increment pk. But I don't know why the auto_increment works only when I start the web service. Later, hibernate just overwrite the last record without create a new one with the auto incremented primary key.
Into the application.properties I have this configuration:
spring.jpa.hibernate.ddl-auto=none
spring.datasource.url=jdbc:mysql://localhost:3306/civicsense?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=AAAAAAA
Some help will be appreciated
First, change your int to Long. And you can omit the strategy, since for MySQL GenerationType.IDENTITY is the same as GenerationType.AUTO which is equivalent to just add #GeneratedValue.
#Id #GeneratedValue
private Long id;
Also, your problem might be the way you are adding your entity. You might want to use saveAndFlush() in this case, since changes will be flushed to DB immediately in this command, which might be prevent your issue, because your actual method might not being committing on time.
You need to change:
#GeneratedValue(strategy = GenerationType.IDENTITY)
for
#GeneratedValue(strategy = GenerationType.AUTO)
and in the application.properties use:
spring.jpa.hibernate.ddl-auto=update

multithreading and hibernate entity id generator

Recently, i have converted my entities to be portable.
We like that our entities can be use with oracle database and mysql(Before it's only oracle).
Before, to generate an entity id, we use SequenceGenerator and now we have changed to GenericGenerator.
Old code :
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_1")
#SequenceGenerator(name = "SEQ_1", sequenceName = "SEQ_1", allocationSize = 1)
public Long getId() {
return this.id;
}
New code :
#GenericGenerator(name="SEQ_1", strategy="org.hibernate.id.enhanced.SequenceStyleGenerator",
parameters={
#Parameter(name="sequence_name",value="SEQ_1"),
#Parameter(name="optimizer", value="seqhilo"),
#Parameter(name="initial_value",value="1"),
#Parameter(name="increment_size",value="1")
})
public Long getId() {
return this.id;
}
And My problem is that, we have many exception on entities creation when we work on multithreading.
We use 3.3.2 of version Hibernate.

Get Id of the associated object after save

There is simple model of associated entities:
MainModel class
#Entity
#Table(name = "main_model")
public class MainModel
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "id_main_model", referencedColumnName = "id")
private List<AssociatedModel> am_collection;
public MainModel() { }
public long getId()
{
return this.id;
}
public void addAssociated(AssociatedModel am)
{
am_collection.add(am);
}
}
AssociatedModel class
#Entity
#Table(name = "associated_model")
public class AssociatedModel
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
public AssociatedModel() { }
public long getId()
{
return this.id;
}
}
Simplest jpa repository for MainModel
public interface MainModelDAO extends JpaRepository<MainModel, Long>
{
}
and finally, controller's method for creating and saving AssociatedModel instance
#RequestMapping("/url")
public String createAssociated(#RequestParam("id_mainmodel") long id_mainmodel, #RequestBody AssociatedModel newAm)
{
MainModel mm = MainModelDAOobject.findOne(id_mainmodel);// MainModelDAOobject - #Autowired
mm.addAssociated(newAm);
MainModelDAOobject.saveAndFlush(mm);
return String.valueOf(newAm.getId());// get Id of associated saved object
}
Associated obect saves into database correctly, but id value of this object, allowed by its getId() method, always zero. How can I get Id of the saved associated object correctly?
Try calling MainModelDAOobject.flush() after saving the value, but before reading the ID.
See this answer for an explanation.
Edit: try manually saving newAm by adding a new line:
mm.addAssociated(newAm); // Existing line
newAm = MainModelDAOobject.save(newAm); // New line
MainModelDAOobject.save(mm); // Existing line
you need a sequencegenerator:
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "MainModel SequenceGenerator")
#SequenceGenerator(name = "MainModel SequenceGenerator", sequenceName = "MainModel Sequence", initialValue = SEQUENCE_INITIAL_VALUE, allocationSize = SEQUENCE_ALLOCATION_SIZE)
Thanks to David Levesque for helpful suggestion.
problem is solved as follows:
need additional repository for AssotiatedModel
public interface AssotiatedModelDAO extends JpaRepository {}
then just save associated object manually:
mm.addAssociated(newAm);
newAm = AssotiatedModelDAOobject.save(newAm);
newAm = MainModelDAOobject.save(newAm)`;
MainModelDAOobject.save(mm);

MappedSuperclass - Change SequenceGenerator in Subclass

I'm using JPA2 with Hibernate and try to introduce a common base class for my entities. So far it looks like that:
#MappedSuperclass
public abstract class BaseEntity {
#Id
private Long id;
#Override
public int hashCode() {
// ...
}
#Override
public boolean equals(Object obj) {
// ...
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
}
However, for every table theres a sequence $entityname_seq which I want to use as my sequence generator. How can I set that from my subclass? I think I need to override #GeneratedValue and create a new SequenceGenerator with #SequenceGenerator.
Yes, it is possible. You can override the default generator name with the #SequenceGenerator annotation.
Base class
#MappedSuperclass
public abstract class PersistentEntity implements Serializable
{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "default_gen")
protected Long id = 0L;
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
}
Sequence (SQL)
create sequence role_seq;
Derived class
#Entity
#Table(name = "role")
#SequenceGenerator(name = "default_gen", sequenceName = "role_seq", allocationSize = 1)
public class Role extends PersistentEntity implements Serializable
{
private static final long serialVersionUID = 1L;
#NotNull
#Size(max = 32)
private String name;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}
This approach worked fine in Hibernate 4.1.x, but it didn't in EclipseLink 2.x.
edit
As per the comment, it seems to be working with EclipseLink 2.6.1-RC1.
In JPA that cannot be done with annotations. Annotation itself cannot be overridden. Entity inherits all the mapping information from MappedSuperClass. There is only two annotations that can be used to redefine mappings inherited from mapped superClass:
AttributeOverride to override column mappings and
AssociationOverride to override join columns / table.
Neither of them helps with GeneratedValue.
With EclipseLink, you can use a Customizer. DescriptorCustomizer interface defines a way to customize all the information about a jpa descriptor (aka a persistent entity).
public class SequenceCustomizer implements DescriptorCustomizer {
#Override
public void customize(ClassDescriptor descriptor) throws Exception {
descriptor.setSequenceNumberName(descriptor.getTableName());
}
}
and in your mapped superclass:
#MappedSuperclass
#Customizer(SequenceCustomizer.class)
public abstract class AbstractEntity implements Serializable {
...
}
I'm writing this as it gets too unreadable as the comment on the accepted answer:
I have a BaseEntity that every other Entity inherits from:
BaseEntity.java:
#MappedSuperclass
public abstract class BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_ID")
private Long id;
I then have two Entities User and Order that both inherit from BaseEntity whilst also having the #SequenceGenerator annotation:
User.java:
#SequenceGenerator(name = "SEQ_ID", sequenceName = "SEQ_USER", allocationSize = 1)
public class User extends BaseEntity { ... }
Order.java:
#SequenceGenerator(name = "SEQ_ID", sequenceName = "SEQ_ORDER", allocationSize = 1)
public class Order extends BaseEntity { ... }
It works on H2 at least with 2 Sequences SEQ_USER and SEQ_ORDERS:
select SEQ_USER.nextval from dual;
select SEQ_ORDERS.nextval from dual;

Categories

Resources