I wanna create a compound primary key, one field of which is autogenerated (JPA).
Can I do this ? Is it possible some how to get a generator from spring environment ?
My entity code is
#Entity
#IdClass(value = IntemKey.class)
public class Item implements Serializable {
#Id // wanna autogenerate this field
private Long id;
#Id
private Date add;
private Date del;
....
getter/setter
}
#Embeddable
public class ItemKey implements Serializable {
private Long id;
private Date add = new Date();
...
getter/setter + equals + hashCode
}
table with data
id add del
1 2015.01.01 null
2 2015.01.03 2015.01.05
2 2015.01.05 null
It can be created by Hibernate, check here for more information.
#Id // wanna autogenerate this field
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
*EDIT : * For compound key check this blog post
Related
Hi I have couple of Entity classes as below, using lombok for getter and setters
Parent Entity Class have
#Table(name = "PARTY")
#Entity
public class Party {
#Id
#Column(name = "PARTY_ID")
private Long partyId;
#OneToMany(targetEntity = DVLoanParticipants.class,cascade = CascadeType.ALL)
#JoinColumn(name = "PARTY_ID")
#MapKey(name="dvpParticipantName")
#LazyCollection(LazyCollectionOption.FALSE)
private Map<String, DVLoanParticipants> dvLoanParticipantsMap;
}
Child Entity Class have
#Table(name = "DV_LOAN_PARTICIPANTS")
#Entity
public class DVLoanParticipants implements Serializable {
#Id
#Column(name = "PARTY_ID")
private Long partyId;
#Id
#Column(name = "DVP_PARTICIPANT_NAME")
private String dvpParticipantName;
#Column(name = "DVP_PARTICIPANT_TYPE")
private String dvpParticipantType;
}
In service class i am calling save operation as
repository.save(parentEntityObject);
I am able to execute update statements ,but when i try to insert new row for child entity class i am getting an error saying
cannot insert NULL into ("ABC"."DV_LOAN_PARTICIPANTS"."PARTY_ID")
But if i print the parentEntityObject just before the save operation i see the values like
(partyId=12345678, dvpParticipantName=XYZ, dvpParticipantType=VKP)
I see the query formed as
insert
into
DV_LOAN_PARTICIPANTS
(DVP_PARTICIPANT_TYPE, PARTY_ID, DVP_PARTICIPANT_NAME)
values
(?, ?, ?)
Just before te save i am seeing valules in the Object
Builder=DVLoanParticipants(partyId=123456, dvpParticipantName=Builder,
dvpParticipantType=Individual)
Update
This is the setting part for values
DVLoanParticipants dvLoanParticipants = new
DVLoanParticipants();
dvLoanParticipants.setPartyId(Long.valueOf(partyId));
dvLoanParticipants.setDvpParticipantName("Builder");
dvLoanParticipants.setDvpParticipantType("Individual");
Party party = new Party();
Map<String, DVLoanParticipants> dvLoanParticipantsMap = new
java.util.HashMap<>();
dvLoanParticipantsMap.put("Builder", dvLoanParticipants);
party.setPartyId(Long.valueOf(partyId));
party.setDvLoanParticipantsMap(dvLoanParticipantsMap);
repository.save(party);
What is the mistake i am doing ?
The root cause of your problem in this part:
#OneToMany(targetEntity = DVLoanParticipants.class,cascade = CascadeType.ALL)
#JoinColumn(name = "LOAN_ID")
#MapKey(name="dvpParticipantName")
private Map<String, DVLoanParticipants> dvLoanParticipantsMap;
actually for your case the column name in the #JoinColumn means:
If the join is for a unidirectional OneToMany mapping using a foreign key mapping strategy, the foreign key is in the table of the target entity.
So, assuming for the clarity that you want to map the following schema:
create table PARTY
(
PARTY_ID int,
-- ...
primary key (PARTY_ID)
);
create table DV_LOAN_PARTICIPANTS
(
PARTY_ID int,
DVP_PARTICIPANT_NAME varchar(50),
DVP_PARTICIPANT_TYPE varchar(10),
-- ...
primary key (PARTY_ID, DVP_PARTICIPANT_NAME),
foreign key (PARTY_ID) references PARTY(PARTY_ID)
);
You can use the following mapping:
#Entity
#Table(name = "PARTY")
public class Party
{
#Id
#Column(name = "PARTY_ID")
private Long partyId;
// I use fetch = FetchType.EAGER instead of deprecated #LazyCollection(LazyCollectionOption.FALSE)
// targetEntity = DVLoanParticipants.class is redundant here
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "PARTY_ID") // this is DV_LOAN_PARTICIPANTS.PARTY_ID column
#MapKey(name = "dvpParticipantName")
private Map<String, DVLoanParticipants> dvLoanParticipantsMap;
public Party()
{
dvLoanParticipantsMap = new HashMap<>();
}
// getters / setters
public void addParticipant(DVLoanParticipants p)
{
this.dvLoanParticipantsMap.put(p.getDvpParticipantName(), p);
p.setPartyId(getPartyId());
}
}
#Entity
#Table(name = "DV_LOAN_PARTICIPANTS")
public class DVLoanParticipants implements Serializable
{
#Id
#Column(name = "PARTY_ID")
private Long partyId;
#Id
#Column(name = "DVP_PARTICIPANT_NAME")
private String dvpParticipantName;
#Column(name = "DVP_PARTICIPANT_TYPE")
private String dvpParticipantType;
// getters / setters
}
and example how to save:
Party party = new Party();
party.setPartyId(2L);
// ...
DVLoanParticipants part1 = new DVLoanParticipants();
part1.setDvpParticipantName("Name 3");
part1.setDvpParticipantType("T1");
DVLoanParticipants part2 = new DVLoanParticipants();
part2.setDvpParticipantName("Name 4");
part2.setDvpParticipantType("T1");
party.addParticipant(part1);
party.addParticipant(part2);
repository.save(party);
and several notes:
The LazyCollectionOption.TRUE and LazyCollectionOption.FALSE values are deprecated since you should be using the JPA FetchType attribute of the #OneToMany association.
You use hibernate specific approach for mapping сomposite identifiers. As it's mentioned in the hibernate documentation:
The restriction that a composite identifier has to be represented by a primary key class (e.g. #EmbeddedId or #IdClass) is only JPA-specific.
Hibernate does allow composite identifiers to be defined without a primary key class via multiple #Id attributes.
But if you want to achieve more portability you should prefer one of the jpa allowed approaches.
I have modified the design of CPRQ a bit to help my database pattern
I have an Employee table and a Department table. Both have common properties
#Column(name="tenantIDPKFK")
private Integer tenantIdpkfk;
#Column(name="status")
private Integer status;
So I created a base class ABaseEntity like below
public class ABaseEntity {
public ABaseEntity() {
}
public ABaseEntity(int tenantIdpkfk, int status) {
this.tenantIdpkfk = tenantIdpkfk ;
this.status = status ;
}
#Column(name="tenantIDPKFK")
private Integer tenantIdpkfk;
#Column(name="status")
private Integer status;
I have extended EmployeeEntity with ABaseEntity
#Entity
#Table(name = "employee")
public class EmployeeEntity extends ABaseEntity{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "first_name")
#NotEmpty(message = "Please provide a name")
#NotBlank
private String firstName;
My CommandHandler runs the following code
EmployeeEntity savedEmployeeEntity = this.employeeRepository.saveAndFlush(employee);
this.mediator.emit(new EmployeeCreatedEvent(savedEmployeeEntity.getId()));
Database saved the object, but only id, firstname. Does not save tenant and status columns.
I know I am missing something silly. Please help.
EDIT
Adding #MappedSuperclass to the ABaseEntity class fixed the issue.
#MappedSuperclass
public class ABaseEntity {...}
Database saved the object, but only id, firstname. Does not save
tenant and status columns.
By default JPA doesn't consider the parent class in the orm (object-relational mapping) of the current class.
You have to specify on the parent class #Inheritance with the strategy to use or use the default one.
For example :
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class ABaseEntity {...}
More info here.
I am using an #Entity with a CrudRepository to create an entry in my MySQL database, and I was wondering at what point the #GeneratedValue(strategy = GenerationType.AUTO) execute and generate the auto increment value?
#Entity
#Table(name = "all_contacts")
public class Contact {
//Ideally this would be set as foreign key to application's user schema
private long userId;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column( name="contactid")
private long contactId;
#NotNull
private String name;
//getters and setters
}
//
public interface ContactRepository extends CrudRepository<Contact, Long> { }
I ask because I want to access the value of the contactId through its getter, but do I have to wait until the ContactRepository.save() is called?
We can't know the new assigned id of that entity prior to executing the SQL INSERT statement.
So, yes you need to ContactRepository.save() or any command that trigger SQL INSERT statement before can get that id. But save is better because it is guaranteed that it will always return ID.
We get the generated value once SQL insert statement is executed. We can't know the value is being assinged before save(). GenerationType.AUTO number generator generates automatic object IDs for entity objects and this generated numeric value is used for primary key field.
#Entity
public class Entity {
#Id #GeneratedValue(strategy=GenerationType.AUTO) int id;
}
I have two tables. I want to make between them relationship, but the thing is that the child table connects to an attribute in a parent node, which is not a PK. How can I assign a non-PK field as a FK for a table?
Here are the tables. User Information:
#Entity
#Table(name="user")
public class userinformation implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="USER_ID")
private int uID;
#Column(name="LIB_ID")
private String libID;
//Other attributes
}
Lib Information
#Entity
#Table(name="libinfo")
public class Auth {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="AUTH_ID")
private int authID;
#Column(name="LIB_ID")
private String lib_ID;
//Other attributes
}
They both should be linked through libID (surely unique). Any idea how to implement it correctly?
Given:
class User {
#Column(name = "lib_id")
private String libID;
}
you must map the Auth entity as:
class Auth {
#JoinColumn(name = "lib_id", referencedColumnName = "lib_id")
#ManyToOne
private User user;
}
Basically, referencedColumnName is used to inform the JPA provider that it should use a column other than the primary key column of the referenced entity (which is used by default with #ManyToOne mappings).
i have first entity :
#Entity
#Table(name="TABLE_ONE")
public class TableOne implements Serializable {
#Id
#Column(name="ID")
private Integer id;
#ManyToOne
#JoinColumn(name="TABLE_TWO_ID", nullable = false)
private TableTwo tableTwoId;
and the second table entity :
#Entity
#Table(name="TABLE_TWO")
public class TableTwo{
#Id
#Column(name="ID")
private Integer id;
, but then after i compile , the result is :
ERROR: column "table_two_id" does not exist
I want to get ID from TableTwo.
Joincolumn annotation tells hibernate the foreign key join column name, in this case I guess it's ID.