I have a primary key in my entity table which is autogenerated but now I want unique keys to be auto generated so how to do it
Please help me out.
#Entity
#Table(name = "director")
public class Director {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long id;
//how to make this field auto generated like above one
#Column(name = "subid", unique=true)
private long sub_id;
My database table picture is here please refer
You can use timestamp or static AtomicLong counter as sub_id value. Try to define method with annotation #PrePersist in your entity class and your JPA provider will execute it before persisting an object.
Note: using timestamp in concurrent environment may lead to collisions and values won't be unique.
private final static AtomicLong subIdCounter = new AtomicLong(System.nanoTime());
#PrePersist
void sub_id() {
this.sub_id = subIdCounter.incrementAndGet();
}
After a short study it seems that that Hibernate supports the feature of generated values only with fields annotated with #Id. With #Id and default #generatedValue Hibernate creates - depending on the database and dialect used - appropriate way to generate the value of id field. usually this is something like creating a sequence and setting the column definition like (examples are from Postgres 12):
id bigint not null nextval('director_id_seq'::regclass)
Interesting thing is that this is done by issuing create statement like this:
create table director (id bigserial not null, primary key (id))
So, the column type bigserial actually generates sequence that is used to insert default value to the id column.
There are two options it you want to generate the value for column sub_id as it is generated to the column id. Both are database dependent.
Just create the sequence manually to the database and alter column sub_id to fetch the default value from the sequence.
OR
Change your column definition to use appropriate column type, like:
#Column(name = "subid", insertable = false,
nullable = false, unique = true, columnDefinition = "bigserial")
private long sub_id;
This will cause Hibernate to generate table like:
create table director (id bigserial not null, subid bigserial not null, primary key (id))
and result to a column like:
subid bigint not null nextval('director_subid_seq'::regclass)
But again: this is database specific stuff.
Also note: that JPA is aware only of the value that is stored to the id field. The subid is inserted to the database table but the sub_id field is not populated until entity is refreshed in its persistence context.
Related
I am having a hard time mapping the following database schema on Hibernate:
The tb_order is an existing table and it is already mapped on Java class. The tb_external_order_details table was recently created and it only have two columns. Both columns are part of the composite Primary Key. The tb_order_id column references to the id column on tb_order table and the external_order_id is just a loose id that doesn't references any column on database.
Please note that the database table and column names are not exactly equal to the Java classes and attributes names. e.g. the java class name is Order and the table name is tb_order. I just think this is important to note because the table/column names inferred by Hibernate may not match (also the table column is snake_case while properties on java classes will be camelCase).
I tried many solutions found here on stack overflow and none of them worked. Also, on the examples I found, no column of the composite Primary Key is a Foreign Key referencing another column of another table.
Try this:
#Entity
public class Order {
#Id
Integer id;
String type;
#OneToMany(mappedBy = "order")
Set<ExternalOrderDetails> externalOrderDetails;
}
#Entity
public class ExternalOrderDetails {
#EmbeddedId
ExternalOrderDetailsId id;
#ManyToOne(fetch = LAZY)
#JoinColumn(name = "tb_order_id", insertable = false, updatable = false)
Order order;
}
#Entity
public class ExternalOrderDetailsId {
#Column(name = "tb_order_id")
Integer orderId;
#Column(name = "external_order_id")
Integer externalOrderId;
}
This is my scenario. I have a Parent table Files_Info and a child table Files_Versions.
create table files_info(
id bigint primary key,
name varchar(255) not null,
description varchar(255) not null,
last_modified TIMESTAMP,
latest_version integer default 0 not null
);
create table files_versions(
id bigint primary key,
file_id bigint references files_info(id),
version integer not null,
location text not null,
created TIMESTAMP,
unique(file_id, version)
);
This is mainly to track a file and its various versions. When the user initiates a new file creation (not yet uploaded any version of the file), an entry is made to the files_info table with basic info like name, description. The latest_version will be 0 initially.
Then when the user uploads the first version, an entry is created in the files_versions table for that file_id and the version
value is set as parent's latest_version + 1. Parent's latest_version is now set to 1.
The user can also upload an initial version of the file when he/she initiates a new file creation. In that case, parent record
will be created with latest_version as 1 and also the corresponding version 1 child record.
I do not know how to design this using JPA / Hibernate.
I wrote my Entity and Repository classes and the save methods seem to work independently. But I do not know how to do the simultaneously latest_version updates.
Can this be done using JPA / Hibernate? Or should it be a database trigger?
A trigger is a valid option, but It can be done using JPA/Hibernate.
I'll suggest to use #PrePersist annotation on some method defined at the files_versions entity ... This method will be called by JPA when you execute: EntityManager.persist(FileVersion); and it can be use to update entity's derivative attributes ... In your case, will be the sum of the file last_version + 1 ... Example:
#Entity
#Table(name = "files_info")
public class FileInfo {
}
#Entity
#Table(name = files_versions)
public class FileVersion {
... //some attributes
#Column(name = "version")
private int version;
#ManyToOne
#JoinColumn(name = "file_id")
private FileInfo fileInfo;
... //some getters and setters
#PrePersist
private void setupVersion() {
// fileInfo should be set before of calling persist()!
// fileInfo should increase its lastest Version before of calling persist()!
this.version = this.fileInfo.getLastVersion();
}
}
I want to create a java class that contains only 1 column from OneToMany ManyToOne etc. type connection not the whole row.
How can I do that?
(I'm not sure that I could express myself so I made an example)
TABLE e_skill
(
id int NOT NULL AUTO_INCREMENT,
skill_name VARCHAR (20) NOT NULL,
PRIMARY KEY (id)
);
TABLE t_person
(
id int NOT NULL AUTO_INCREMENT,
user_id int NOT NULL,
primary_skill int,
PRIMARY KEY (id),
FOREIGN KEY (primary_skill) REFERENCES e_skill(id)
);
TABLE t_secondaryskills
(
id int NOT NULL AUTO_INCREMENT,
t_person_id int NOT NULL,
skill_name int NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (t_person_id) REFERENCES t_person(id),
FOREIGN KEY (skill_name) REFERENCES e_skill(id)
);
public enum Skill {
...
}
#Entity
#Table(name = "t_person")
public class Employee {
#Id
#GeneratedValue
private Integer id;
#ManyToOne
#Enumerated(EnumType.STRING)
//????????
//get skill_name column from e_skill
//????????
private Skill primarySkill;
#OneToMany
#Enumerated(EnumType.STRING)
//????????
//get skill_name column from e_skill
//????????
private Set<Skill> secondarySkills;
//getters setters
}
The only way I could do it now is to create a Entity to represent the e_skill table, I want to avoid that, because I only need 1 column from it.
If I understand your question correctly, you can't do what you want because of the secondary skills (because it's a collection). You can only map the primary skill name though using the #SecondaryTable annotation.
When you map things using an ORM there's no such thing as I only want a column in this scenario as you're mapping Objects, and usually in your objects you don't want to replicate data (unless they are outside your domain model). If this is unacceptable for you, I suggest you to take a look at other tools like myBtais, which gives you full control on the data you get back.
So bottom line, map your skill as an entity and live with it even if it has many columns, or choose a different tool (but not an ORM).
Hello I have a Problem with JPA and SQLite.
I have a table called Category in SQLite. This is the Structur of this table:
Category:
catID INTEGER Primary Key
catName TEXT
Now i'm trying to insert a new Category via JPA.
This is my method to do this:
public void insertCategory(EntityManager em, String catName) {
Category cat = new Category();
cat.setCatName(catName);
em.getTransaction().begin();
em.persist(cat);
em.flush();
em.getTransaction().commit();
}
Now I have an Execption at em.flush().
The Exception says
Null or zero primary key encountered in UnitOfWork clone
I know this happens because of the Object cat. The catID is still null.
The class looks like:
#Entity
#Table(name="Category")
public class Category implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name="catName")
private String catName;
#Id
#Column(name="catID")
private Integer catID;
+ Getter and Setter
}
SQLite increments the Primary Key automatically when not given in the query. How can i inform my Program about the Primary Key to run without getting this Exception??
Thank you Mick Mnemonic for your help. The last answer you give helped me.
I had to generate my database new and add the autoincrement Argument to my Primary Keys. Then the sqlite_sequence Table was generated. Now i can insert Entitys in my database via JPA without getting any Exception.
This is my Generator Annotation:
#GeneratedValue(generator="sqlite")
#TableGenerator(name="sqlite", table="sqlite_sequence",
pkColumnName = "name", valueColumnName = "seq",
pkColumnValue = "Section", initialValue = 1,
allocationSize = 1)
the last two Arguments are necessary because jpa seems to add +50 to the value in the sqlite_seq table and SQLite begins the Autoincrement value at 1.
I have a MySQL table to hold tags (i.e. like those used here on Stack Overflow). It simply has an id (pk) and a tag column to hold the tag itself.
The annotated get methods for my Tag entity are shown below.
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, nullable = false)
public int getId() {
return this.id;
}
#Column(name = "tag", unique = true, nullable = false)
public String getTag() {
return this.tag;
}
I am using a unique column constraint on tag as there should never be more than one row for a given tag. However, Hibernate appears to be ignoring this, i.e. I can save the exact same tag many times and it simply creates a new row rather than throwing an exception.
Am I missing something or should this be working?
From JavaDoc of UniqueConstraint (unique=true on #Colunm is just a shortcut):
This annotation is used to specify that a unique constraint is to be included in the generated DDL for a primary or secondary table.
So it does not seem to enforce uniqueness upon inserts. You should create a unique constraint in the database in any case.
You miss that this is only a information.
You should add also constraint on the column in database.