Spring data JPA only one composite key is auto incremented issue - java

I am using MySQL database.
In my table i there are two four primary keys, out of which one is auto incremented.
#Embeddable
public class EmployeeId implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Column(name = "id", nullable = false)//
This is just Pk in mysql table
**private int id;**
// I have tried and #GeneratedValue(strategy = GenerationType.IDENTITY),
#GeneratedValue(strategy = GenerationType.IDENTITY)
//and #GeneratedValue(strategy = GenerationType.TABLE)
//#GeneratedValue(strategy = GenerationType.AUTO, generator = "id") #SequenceGenerator(name = "id", sequenceName = "id")
**this is auto incremented and pk in mysql table**
#Column(name = "gender_key", nullable = false)
private int gender_key;
}
#Entity
#Table(name = "employee")
public class employee {
#EmbeddedId
private EmployeeId employeeId;
private String emp_name;
private String mobile_no;
employee() {
}}
public interface employeeRepository extends
JpaRepository<employee, EmployeeId> {
}
In My Controller I want id after employeeRepository.save(bean); method because i want to save that id in different db .
logger.info("gender_key is --- > "+gender_key);
But I am getting always 0 value of gender_key.
The thing which I have tried is:
bean = employeeRepository.save(bean)
int gender_key= bean.getGender_key();
logger.info("gender_keyis --- > "+gender_key);
But still the value for gender_key is 0(Zero).
Or any Query which I have to write in repository .
How I can get the auto incremented value of gender_key which is inserted into MySQL table?
Please Help.
Thanks in advance.

Your JPA #Id does not need to match the database PK column(s). So long as it is unique then that is all that matters.
From https://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing:
The JPA Id does not always have to match the database table primary
key constraint, nor is a primary key or a unique constraint required.
As your an auto-increment column is guaranteed to be unique then just use gender_key as your #ID and map id as a normal column.
#Entity
#Table(name = "employee")
public class employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int genderKey;
#Column
private int id;
}
To be honest I would find your schema confusing however.
I would also suggest reading the following:
https://www.javatpoint.com/java-naming-conventions

You're missing a #GeneratedValue at the id field.
Depending on its values, you're free to choose a strategy for generation, like a sequences, id tables, an automatic internal id generation.
Last but not least GenerationType.AUTO will choose one of the mentioned strategies.
See the Javadocs for javax.persistence.GeneratedValue and javax.persistence.GenerationType.

Related

JPA/Hibernate Spring boot-primary key one entity referred as an instance to other entity not working

I have generated master tables using liquibase. I have created the corresponding models in spring boot now I want to maintain a relation ship between those models.
I have one table called Vehicle_Type, it is already pre-populated using liquibase.
#Data
#Entity
#Table(name="VEHCILE_TYPE")
public class VehicleType {
#Id
private int id;
#Column(name="DISPLAY_NAME")
private String displayName;
#Column(name="TYPE")
private String type;
#Column(name="CREATED_DATE")
private LocalDateTime createdDate;
#Column(name="UPDATED_DATE")
private LocalDateTime updateDate;
}
now what I want to achieve is, I have one child entity, I have refer the VehicleType instance inside that entity as depicted below
#Data
#Entity
#EqualsAndHashCode(callSuper = true)
#Table(name = "NON_MSIL_VEHICLE_LAYOUT")
public class NonMsilVehicleLayout extends BaseImagesAndLayout {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "NMV_SEQ")
#SequenceGenerator(sequenceName = "NON_MSIL_VEH_SEQUENCE", allocationSize = 1, name = "NMV_SEQ")
private int id;
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "VEH_TYPE", referencedColumnName = "id")
private VehicleType vehicleType;
public interface VehType {
String getVehType();
}
}
The problem is when I tries to save entity NonMsilVehicleLayout, then it tries to first insert the data in VEHICLE_TYPE table also. which should not going to be happen.
I don't want that, I want JPA will pick the correct ID from VEHICLE_TYPE table and place it inside the corresponding table for NonMsilVehicleLayout, because the id of VEHICLE_TYPE table is act as foreign key in Non_Msil_Vehicle_Layout table.
log.info("Inside saveLayout::Start preparing entity to persist");
String resourceUri = null;
NonMsilVehicleLayout vehicleLayout = new NonMsilVehicleLayout();
VehicleType vehicleType=new VehicleType();
vehicleType.setType(modelCode);
vehicleLayout.setVehicleType(modelCode);
vehicleLayout.setFileName(FilenameUtils.removeExtension(FilenameUtils.getName(object.key())));
vehicleLayout.setS3BucketKey(object.key());
I know I missed something, but unable to figure it out.
You are creating a new VehicleType instance setting only the type field and set the vehicleType field of NonMsilVehicleLayout to that new instance. Since you specified CascadeType.ALL on NonMsilVehicleLayout#vehicleType, this means to Hibernate, that it has to persist the given VehicleType, because the instance has no primary key set.
I guess what you rather want is this code:
vehicleLayout.setVehicleType(
entitManager.createQuery("from VehicleType vt where vt.type = :type", VehicleType.class)
.setParameter("type", typeCode)
.getSingleResult()
);
This will load the VehicleType object by type and set that object on NonMsilVehicleLayout#vehicleType, which will then cause the foreign key column to be properly set to the primary key value.
Finally, after some workaround, I got the mistake, the column name attribute was incorrect, so I made it correct and remove the referencedColumn and Cascading.
Incorrect:
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "VEH_TYPE", referencedColumnName = "id")
private VehicleType vehicleType;
Correct:
#OneToOne
#JoinColumn(name = "VEHICLE_TYPE")
private VehicleType vehicleTypes;
also I have added the annotation #Column in the referende entity VehicleImage
public class VehicleType {
#Id
#Column(name = "ID") // added this one
private int id;
}
That bit workaround solved my problem, now I have achieved what I exactly looking for.

How to enforce JPA to use composite primary key index order

table Name : Transfer
Columns : IDENTIFIER,KEY,TRANSFER_NUMBER,FIRST_NAME,LAST_NAME
Transfer's table composite primary keys are : IDENTIFIER,KEY,TRANSFER_NUMBER
Transfer's table Index INDEX1 definition : IDENTIFIER ASC, KEY ASC, TRANSFER_NUMBER ASC
Transfer pojo
#Entity
#Table(name = "TRANSFER", indexes = { #Index(name = "INDEX1", columnList = "identifier,key,transferNbr") })
#Getter
#Setter
#DynamicUpdate
public class Transfer implements Serializable, Cloneable {
private static final long serialVersionUID = 1L;
#EmbeddedId
private TransferPk id;
#Column(name = "FIRST_NAME")
private String firstName;
#Column(name = "LAST_NAME")
private String lastName;
TransferPk pojo
#EqualsAndHashCode
#Getter
#Setter
#Embeddable
public class TransferPk implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "IDENTIFIER")
private String identifier;
#Column(name = "KEY")
private int key;
#Column(name = "TRANSFER_NUMBER")
private String transferNbr;
Code to retrieve Transfer
TransferPk id = new TransferPk();
id.setIdentifier("123");
id.setKey(456);
id.setTransferNbr("789");
// This JPA query also uses the reverse Transfer of index
Optional<Transfer> Transfer = TransferRepo.findById(id);
I'm able to get data from DB without any issues and HQL is
select <all fileds> from TRANSFER transfer0_ where transfer0_.TRANSFER_NUMBER=? and transfer0_.KEY=? and transfer0_.IDENTIFIER=?
Though we used indexes annotation, still JPA is not using the index defined in Transfer table (INDEX1) and hence retrival takes more time.
How to enforce JPA to use index order. Any help is highly appreciated. Thank you
I don't know what you mean by "index order" but you are using JPA attribute names in the #Index annotation which is wrong. Use column names like #Index(name = "INDEX1", columnList = "identifier,key,transfer_number")
1st of all the way you are creating index is wrong. column List will have always table column name rather than field name.
In your case it would be:---
#Table(name = "TRANSFER", indexes = { #Index(name = "INDEX1", columnList = "IDENTIFIER,KEY,TRANSFER_NUMBER ASC") })
"DESC/ASC" is used for Index order.
Hope , It should resolve your issue.

Hibernate Unknow Column at save() after rename column

I had a column useless_id in table foo. This column is foreign key into other table.
I have mapped it like this
#Entity
#Table(name = "foo")
public class Foo{
#Column(name = "useless_id")
private Integer uselessId;
//...
}
Everything worked perfect. But I decided to change the name of column useless_id into useful_id.
After that appear problems. When I try to save an Foo object: session.save(new Foo(...)) I get Unknown column F.useless_id in 'where clause'.
The query is printed in console insert into foo (..., useful_id, ...) value (...)
In list of columns I don't see useless_id.
Why I get Unknow column useless_id in 'where clause' ? Why use where when insert?
It is was changed everywhere. Even in Foo object
I get this error only when try to save.
UPDATE(Foo class is Order Class and useful_id is customer_id):
#Entity
#Table(name = "orders")
public class Order{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "status")
private Integer status;
#Column(name = "customer_id")
private Integer customerId;
#Column(name = "shipping_address")
private String shippingAddress;
//setters getters
}
#Entity
#Table(name = "customers")
public class Customer{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "name")
private String name;
//setters getters
}
This is how I try to insert new object
//...
session.beginTransaction();
Order order = new Order();
//set random values. customer_id get valid value, it exists in customers
session.save(order);
session.getTransaction().commit();
session.close();
For DESCRIBE orders; command I get:
Field----------------Type-----------Null---Key---Default---Extra
id-------------------int(11)--------NO-----PRI---NULL------auto_increment
status---------------int(50)--------NO-----------NULL------
customer_id----------int(50)--------NO-----MUL---NULL------
shipping_address-----varchar(191)---NO-----------NULL------
I found the problem.
It raised from MySQL. I found it by tried to insert with SQL command, direct to MySQL. Same error.
So I was looking very carefully in db and I found the problem is from triggers. In one of triggers still use old name of column.
Now make sense: Unknow column useless_id in 'where clause'. That where clause was in trigger which try to find useless_id, but it no longer exists.
CONCLUSION: After change name of column, check triggers.
In your java class you changes column name from useless_id to userful_id, but same think you didnt changes in your DB structure due to which you see this error.

Check whether exist the database object with the specified field values

I am new in Spring Data, and I need to establish the impossibility of creating a new entity in DB if an entity already exists with the same field values.
Comparison condition: if "closeType" field and "id" agreement field of a new entity equal to database entity fields, I can't add this entity to DB. How do it?
My entity:
#Entity
#Table(name = "contract")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Contract implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "contractGenerator")
#SequenceGenerator(name = "contractGenerator", sequenceName = "contract_sequence")
private Long id;
#Column(name = "start_date")
private LocalDate startDate;
#Column(name = "end_date")
private LocalDate endDate;
#Column(name = "first_pay_date")
private LocalDate firstPayDate;
#Column(name = "next_pay_date")
private LocalDate nextPayDate;
//Here is thу first field for comparison
#Enumerated(EnumType.STRING)
#Column(name = "close_type")
private CloseType closeType;
#ManyToOne
#JsonIgnoreProperties("")
private Mentor mentor;
//Here is second ID agreement field for comparison
#ManyToOne
#JsonIgnoreProperties("")
private Agreement agreement;
...............
//getters and setters
I have to block possibility to create several active contracts("closeType") in one agreement ("id")
I have to block possibility to create several active
contracts("closeType") in one agreement ("id")
you could use UniqueConstraint How to introduce multi-column constraint with JPA annotations?
...
#Table(uniqueConstraints={
#UniqueConstraint(columnNames = {"close_type", "agreement"})
})
Contract implements Serializable {
...
}
Thanks, maybe you could hint me how to set constraint for "closeType"
if, for example, only closeType fields with Null value will be uniqe?
But other values of closeType wont be uniqe
How to annotate unique constraint with WHERE clause in JPA says:
creating partial indexes (CREATE INDEX ... ON ... WHERE) using JPA
aren't specified by JPA. You cannot use a unique constraint for this
purpose because unique partial indexes are not unique constraints.
Some JPA providers offer extension annotations specific to that JPA
provider that add features for running native DDL scripts, defining
indexes with annoations, etc. Since you haven't mentioned which JPA
provider you are using I can't tell you more. Here's the documentation
for EclipseLink index DDL;
I suggest you to have a look at the
How to annotate unique constraint with WHERE clause in JPA

Hibernate ForeignKey mapping annotations

I want to have hibernate generate some tables with foreign keys and so on. Ill give you an example of the query i want hibernate to generate:
create table RealtimeCost(id INTEGER not null primary key Autoincrement,
mnemonic varchar(50)not null references Exchange(mnemonic),
sid int not null references License(sid),
price numeric(10,2) not null)
so this query should be generated by hibernate via Annotations. The corresponding class to this is:
#Entity
#Table
public class RealtimeCost {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#MapsId("mnemonic")
#JoinColumn(referencedColumnName="sid")
private String mnemonic;
#MapsId("sid")
#JoinColumn(referencedColumnName="sid")
private Integer sid;
#Column
private Double price;
Example for what the mnemonic in RealtimeCost should be mapped to (each mnemonic in RealtimeCost has exactly 1 value in Exchange):
#Entity
#Table
public class Exchange {
#Id
#Column(name="mnemonic")
private String exchange;
#Column
private String description;
As you can see I've tried a bit with the help of the docs, but I was not able to have the foreign keys be generated by hibernate. It would be really kind, if anyone could tell me the needed annotations and values for this class, so i can do it myself for the other classes as well. Also please tell me if i need to change anything in the Exchange class for the mapping to work. Thanks in advance
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "accommodation_type", unique = true, nullable = false)
private AccommodationType accommodationType;
#ManyToOne()creates a relationship according to #JoinColumn()
name in #JoinColumn() is the table name that you want to make a connection.
Then when you create a class that is going to be connected to main class, you first need to give it a table name below #Entity e.g #Table(name="accommodation_types")
Then you create your variable.
//bi-directional many-to-one association to Accommodation
#OneToMany(mappedBy="accommodationType", fetch=FetchType.EAGER)
private List<Accommodation> accommodations;
value of mappedByis the variable name in main class.
I'm not an expert but we let hibernate do all the work with the javax.persistence annotations for joining entities.
#javax.persistence.ManyToOne( fetch = javax.persistence.FetchType.EAGER, optional = true )
#javax.persistence.JoinColumn( name = "VIEWTYPE_ID", nullable = true, unique = false, insertable = true, updatable = true )
private com.company.other.subproject.ViewType viewType;
Maybe this is what you need. Since this let's hibernate care about the tables that have to be created or not and the foreignKeys get created automatically with the dialect of the database you communicate with.
You should set up the association in one entity and use the mappedBy in the other. You don't need #MapsId because you are not using embedded entities (read the docs). Take a look at the #OneToMany and #ManyToOne relationships:
#Entity
#Table
public class RealtimeCost {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#OneToMany
#JoinColumn(name="mnemonic")
private Exchange exchange;
...
}
#Entity
#Table
public class Exchange {
#Id
#Column(name="mnemonic")
private String mnemonic;
#Column
private String description;
#ManyToOne(mappedBy="exchange")
private RealtimeCost realtimeCost;
...
}
Every answer posted here got an upvote from me, because everyone was kinda right, but it was not 100% what i was searching for, yet it helped me solving my problem by myself. For the example i posted, the solution i was seeking is as follows (i also added not nullable):
#Entity
#Table
public class RealtimeCost {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#ManyToOne
#JoinColumn(name = "mnemonic",nullable=false)
private Exchange exchange;
#ManyToOne
#JoinColumn(name = "sid",nullable=false)
private License license;
#Column(nullable=false)
private Double price;
these are the annotations i was seeking for RealtimeCost class. I did not need any special annotations in Exchange class. #Nico answer was closest to what i need, therefore his answer will be accepted

Categories

Resources