problem to get auto-incremented primary key with hibernate / postgres - java

Using hibernate 5.4, postgres 10 with IntelIiJ Ultimate, impossible to get auto-incremented primary key
with this following code, the sequence "warehouses_id_seq" is created but the primary key is not incremented
#Entity
#Table(name = "warehouses")
#SequenceGenerator(name = "SEQUENCE_WAREHOUSE", sequenceName = "warehouses_id_seq", allocationSize = 1)
public class Warehouse implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQUENCE_WAREHOUSE")
#Column(name = "id")
private Integer id;

I added below line to fix the problem:
#ColumnDefault("nextval('public.warehouses_id_seq')");
But I'm quite desapointed, I expected Hibernate to do it automaticaly with the SequenceGenerator...

Related

How to achieve Batch Inserts with Spring data and SQLite?

I am trying to perform Batch Insert with spring data jpa and Hibernate but the problem is Hibernate only supports batch inserts when the generated value strategy is SEQUENCE but somehow sqlite does not support this strategy so I resort to Identity which works fine but does not support batching with hibernate. Is there any solution or workaround for this.
Entity
#Entity
#Table(name = "party")
public class PartyEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "party_id", nullable = false)
private Long id;
#Column(name = "party_name", unique = true)
#NonNull
private String name;
#Column(name = "party_phone_number", unique = true)
private Long number;
}
SQLite do have this table called 'sqlite_sequence' which I try to use with #SequenceGenerator but hibernate tries to create this table which we cannot as this is a reserved table. And same goes for #TableGenerator.
Annotation for sequence used
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "party_seq")
#SequenceGenerator(name = "party_seq", sequenceName = "sqlite_sequence", allocationSize = 1)
Annotation for table used
#GeneratedValue(strategy = GenerationType.TABLE, generator = "sqlite_generator")
#TableGenerator(name = "sqlite_generator", table = "sqlite_sequence", pkColumnName = "name",
valueColumnName = "seq", pkColumnValue = "party", initialValue = 1, allocationSize = 1)
DDL script for the table
CREATE TABLE party (
party_id INTEGER PRIMARY KEY ASC AUTOINCREMENT,
party_name VARCHAR (256) UNIQUE
NOT NULL,
party_phone_number INTEGER (10) UNIQUE
);

Make #GeneratedValue start a sequence with a specific value

I have a class that is an entity of a table from a PostgreSQL database:
#Entity
#Table(name = "users")
public class User {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Getter private Long id;
...
CREATE TABLE IF NOT EXISTS users (
id BIGSERIAL NOT NULL UNIQUE,
...
When the application starts, this table fills with some test data (from .sql file trough "INSERT INTO..."). However, when a new instance is created in the database trough Hibernate, the ID always starts with one, forcing me to create it multiple times until generated ID reaches the required value.
I need the ID counter to start with a number, that is one more than the ID of the previous record in the table. Ideally not requiring me to manually specify the ID value.
You can define your entity like this:
#Entity
#Table(name = "users")
#SequenceGenerator(name = "sequence", sequenceName = "mySequence")
public class User {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence")
#Getter private Long id;
And then in your .sql file write insert queries like this:
INSERT INTO users values (select nextval('mySequence'), ...
select nextval('mySequence')
will give you next available value from sequence table
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "your_custom_sequence")
#SequenceGenerator(name="your_custom_sequence", sequenceName = "MY_CUSTOM_SEQ", allocationSize=1)
and you can define your sequence in sql like CREATE SEQUENCE MY_CUSTOM_SEQ MINVALUE 1 START WITH 1 INCREMENT BY 1 CACHE 20 NOMAXVALUE;

Not able to save data using OneToOne mapping

I am trying to save data in two table using OneToOne mapping.I have followed
this,this,this,this and few more online resources to accomplish this, but it is throwing
ORA-02291: integrity constraint (TableName.TEST_ID) violated - parent key not found
Creating a table where column TESTID is foreign key. In the parent table TESTID is primary key.That primary key is generated using sequence generator
CREATE TABLE EW_TEST_REFTABLE (
ID int NOT NULL PRIMARY KEY,
TESTNAME VARCHAR2(20) NOT NULL,
TESTID int,
CONSTRAINT test_id FOREIGN KEY(TESTID)
REFERENCES EW_TESTDATA(TESTID)
);
Ew_testdataEntity.java (Entity class of parent table)
#Entity
#Table(name = "EW_TESTDATA")
public class Ew_testdata {
#Id
#SequenceGenerator(name = "sube_seq",
sequenceName = "EW_TESTDATA_SEQ",
allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sube_seq")
#Column(name = "TESTID")
private int testid;
#Column(name = "TESTNAME")
private String testname;
// Ew_test_reftable is another entity class.In that table the column
// TESTID (foreign key) must be same as the primary key of this
// entity/table(EW_TESTDATA)
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "TESTID",unique = true)
private Ew_test_reftable ewtestreftable;
//Constructor
// getter & setter
}
Ew_test_reftable.java
#Entity
#Table(name = "EW_TEST_REFTABLE")
public class Ew_test_reftable {
#Id
#SequenceGenerator(name = "subf_seq", sequenceName = "EW_REF_SEQ", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "subf_seq")
#Column(name = "ID")
private int id;
#Column(name = "TESTNAME")
private String testname;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "TESTID")
private int testid;
//Constructor,getter & setter
}
Service to save data using Jpa
#Override
public Ew_testdata ew_testdata(String name) {
Ew_test_reftable ew_test_reftable = new Ew_test_reftable();
ew_test_reftable.setTestname("test");
Ew_testdata ew_testdata = new Ew_testdata();
ew_testdata.setTestname(name);
ew_testdata.setEwtestreftable(ew_test_reftable);
iew_tEst.ewTestdata(ew_testdata);
return null;
}
The problem seems to be similar to few other problem described in SO but still i am not able to figure out where I am making mistake
Your entity and table structure looks opposite, and that making so much confusion to understand.
Now, referring to exception
ORA-02291: integrity constraint (TableName.TEST_ID) violated - parent key not found
This mean, you don't have reference of parent id in child table when adding new row to child table.
In Ew_test_reftable class, you have
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "TESTID")
private int testid;
If I understand correctly, testid is your foreign key in EW_TEST_REFTABLE, then why are you using GenerationType.IDENTITY ? This will create new sequence id and may not match with parent key and result in error/exception.
As per my understanding of your design,
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "TESTID")
private int testid;
change to
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "TESTID",unique = true)
private Ew_testdata ew_testdata;
And similar to above code should be removed from Ew_testdata entity (There might be slight change here and there)

JPA #MappedSuperclass different Id counters for subclasses

I've got a #MappedSuperclass which is my base-class for all my entities (#Entity, direct or indirect through multiple sub-classing).
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#XmlAttribute(required = true)
private Long primaryKey;
The Id is generated like shown above.
My problem is that the #Id-counter is the same for each #Entity. In fact thats not a big problem because it would take a while to reach the Long.MAX_VALUE. But reaching that maximum value is a lot easier because there is only one counter for all entities. How can I use a different #Id-counter without having to add the above code to all #Entity-classes?
(If it matters for your answer: I'm using a H2-Database.)
If your database and tables support AUTO_INCREMENT change the annotation to this #Id #GeneratedValue(strategy=GenerationType.IDENTITY). Then the id will be generated during commit.
There is another way via TABLE or SEQUENCE strategy, but it needs to be explicitly defined per Entity which is problem for abstract BaseEntity. Just hava a look:
#Entity
#TableGenerator(name="tab", initialValue=0, allocationSize=50)
public class EntityWithTableId {
#GeneratedValue(strategy=GenerationType.TABLE, generator="tab")
#Id long id;
}
EDIT:
Well, so it is possible!
MappedSuperclass - Change SequenceGenerator in Subclass
#Id
#Column(name = "ID", unique = true, nullable = false)
#GeneratedValue(strategy = GenerationType.TABLE, generator = "SEQ_AAAAAAAAAAA")
#TableGenerator(
name = "SEQ_AAAAAAAAAAA",
table = "SEQ_ENTITY" /*<<<==YOUR TABLE NAME FOR SAVE NEXT VALUES HERE*/,
pkColumnName = "ENTITY",
initialValue = 1,
valueColumnName = "NEXT_ID",
pkColumnValue = "packageee.PACK.PAK.YOURCLASSNAME",
allocationSize = 1)
private Long id;

Define primary and foreign keys in same object which use the sequence generators

I have created Address object which has a ID (AddressPK) which get generated by a sequence. The address object also has a foreign key to Client object via the ID of the client object (ClientPK). The ClientPK also generated via a sequence. However, it complains at the time I try to deploy the ear to web logic server saying that only one generated element can exist for an entity. The class snippets as follows. Anyone can help how to define a foreign key using an object that also uses a sequence generator in addition to the object primary key?
public class Address implements Serializable{
#EmbeddedId
private AddressPK id;
#Embedded
private ClientPK clientId;
...
}
#Embeddable
public class AddressPK implements Serializable {
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator="RoidSequenceGenerator")
#SequenceGenerator(name="RoidSequenceGenerator",sequenceName="roid_sequence", allocationSize=1)
#Column(name = "a_roid")
private long value;
...
}
#Embeddable
public class ClientPK implements Serializable {
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator="RoidSequenceGenerator")
#SequenceGenerator(name="RoidSequenceGenerator",sequenceName="roid_sequence", allocationSize=1)
#Column(name = "c_roid")
private long value;
...
}
I think you do not understand what is the Primary Key and what the difference from the Foreign Key. Primary key (PK) can be generated for each database entity. And there is a restriction in JPA that generated value must be only one. Foreign Key (FK) in the other hand is a link to the PK of another entity. So you need to create another entity with generated PK and have a link to it with OneToMany, ManyToMany or another kind of association. For example:
#TableGenerator(name = "entities_id_generator", table = "SEQUENCE",
pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue =
"ENTITY_SEQ", initialValue = 0, allocationSize = 1)
public class DBObject1 implements Serializable {
#Id
#GeneratedValue(generator = "entities_id_generator", strategy = GenerationType.TABLE)
private Long id;
#ManyToOne
#JoinColumn(name = "source_id")
private DBObject2 source;
}
#TableGenerator(name = "entities_id_generator", table = "SEQUENCE",
pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue =
"ENTITY_SEQ", initialValue = 0, allocationSize = 1)
public class DBObject2 implements Serializable {
#Id
#GeneratedValue(generator = "entities_id_generator", strategy = GenerationType.TABLE)
private Long id;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "source")
private List<DBObject1> objects;
}
In example above the virtual FK for entity DBObject1 will be stored in column source_id. It is virtual because there will not be any physical FK in database table. But JPA will link these objects if you ask.

Categories