Embeddable PK Object not populating after persist and flush - java

I have an embedded PK object that doesn't populate the id field after persisting and flushing to the database. The ID is an auto-increment field in the database.
Now normally, I would just try a refresh, but it throws the following error:
"Entity no longer exists in the database: entity.Customers[ customersPK=entity.CustomersPK[ id=0, classesId=36 ] ]."
public class Customers implements Serializable {
#EmbeddedId
protected CustomersPK customersPK;
...
}
#Embeddable
public class CustomersPK implements Serializable {
#Basic(optional = false)
#Column(name = "id")
private int id;
#Basic(optional = false)
#NotNull
#Column(name = "classes_id")
private int classesId;
.....
}
And here's the code that makes the call
Classes cl = em.find(Classes.class, classId);
CustomersPK custPK = new CustomersPK();
custPK.setClassesId(cl.getId());
Customers cust = new Customers(custPK);
em.persist(cust);
em.flush();
// The problem is right here where id always equals 0
int id = cust.getCustomerspk().getId();
Thanks for the help.

Why would the id not be 0, you have never set it?
If it is a generated id, you need to annotate it using #GeneratedValue, otherwise you need to set the value.

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.

Spring data JPA only one composite key is auto incremented issue

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.

Unable to insert into database using JPA. Tried merge, persist and INSERT query

I am trying to add an entry into AttributeName:
#Entity
public class AttributeName implements Serializable
{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "attNameId", nullable = false)
private Long attNameId;
#Column(name = "attName", unique = true, nullable = false, length = 200)
private String attName;
#Column(name = "required", nullable = false)
private boolean required;
...
#Stateless
#LocalBean
public class AttributeNameManagerBean implements AttributeNameManagerRemote
{
#PersistenceContext(unitName = "mainPU")
private EntityManager entityManager;
public AttributeNameManagerBean()
{
}
...
I first must add this entry and use the newly created id to insert into the Attribute which stores this id (to link to an AttributeValue).
I have tried:
AttributeName savedAttName = entityManager.merge(newAttName);
entityManager.persist(newAttName); entityManager.flush();
entityManager.create(Native)Query("INSERT...");
I receive a ConstraintViolationException later but the main problem is that the insert statement in any of the 3 above forms does not throw an exception, but when I query the database the new entry is not there.
In the first example, savedAttName contains the newly generated unqiue PK :S
Note: I am sure that attName is a new unique entry into the database.]
Any help would be greatly appreciated. Happy to provide any more information if required.
Edit: There is an attNameId field in Attribute. Attribute has two unique constraints:
uniqueConstraints={
#UniqueConstraint(columnNames = {"attNameId", "attValueId"} ),
#UniqueConstraint(columnNames = {"sectionId", "sectionIndex"} )}
The sectionId and sectionIndex being entered are a unique combination which doesn't exist currently in AttributeName (which only has 1 entry, which I manually inserted).
Fix:
Removed the constraints from the table, reployed. Then dropped the table, re-added the constraints and it works. I'm guessing it didn't correctly set up the constraints.

Hibernate #Any annotation usage

I have one entity called Change where I need log changes in database like inserting, updating or deleting rows.
So my Change table contains some data and now I would like to add foreign key to record changes in another table, but I have different tables. For example I have Weather table, Group table,... So I have done some searching and I have found a little bit about #Any annotation. So I added some columns to my Change entity:
#Entity
#Table(name = "CHANGE")
public class Change {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "CHANGE_ID")
private int changeId;
...
#Any(metaColumn = #Column(name = "RECORD_TABLE"))
#AnyMetaDef(idType = "int", metaType = "string",
metaValues = {
#MetaValue(targetEntity = Weather.class, value = "WEATHER"),
#MetaValue(targetEntity = Group.class, value = "GROUP"),
...
})
#JoinColumn(name="recordID")
private Object record;
#ManyToOne
#JoinColumn(name = "USER_ID")
private User user;
public Object getRecord() {
return record;
}
public void setRecord(Object record) {
this.record = record;
}
...
And my stupid question is:
How can I insert data into database (like foreign ID and class name) and how could I retrieve them?
Please go through this Link
You should care about your entity relationship (1-1 or 1-M or M-M)

NullPointerException when accessing relationship of jpa entity

I am getting a null pointer exception when i try to call a getter for a relationship. it is my understanding that the container will fill this field in with an appropriate list object whilst the entity is still managed.
the schema was pre-existing so this is a bottom up mapping.
This is my 'one' side entity of the onetomany relationship:
#Entity
#Table(name=CollectorHeader.TABLE_NAME)
public class CollectorHeader implements Serializable {
...
#Id
#Column(name = "COLLECTORHEADERID")
private long id;
#OneToMany(mappedBy="collectorHeader", fetch=FetchType.LAZY)
private List<CollectorDetail> collectorDetails;
...
}
And here is my 'many' side entity :
#Entity
#Table(name = CollectorDetail.TABLE_NAME)
public class CollectorDetail implements Serializable {
...
#Id
#Column(name = "COLLECTORDETAILID", unique = true)
long id;
...
#NotNull
#ManyToOne
#JoinColumn(name = "COLLECTORHEADERID")
private CollectorHeader collectorHeader;
...
public CollectorDetail(long id, #NotNull CollectorHeader collectorHeader,
long provenanceLinkPk, #NotNull String provenanceLinkClass) {
setId(id);
setCollectorHeader(collectorHeader);
setProvenanceLinkPk(provenanceLinkPk);
setProvenanceLinkClass(provenanceLinkClass);
}
}
And this is where i am calling the relationship:
public CollectorDetail createCollectorDetail(long collectorHeaderId, long provenanceLinkPk, #NotNull String provenanceLinkClass) throws SystemException {
CollectorHeader collectorHeader = em.find(CollectorHeader.class, collectorHeaderId);
if(collectorHeader == null) {
String error = "There is no Collector Header with the id: '" + collectorHeaderId + "'";
log.error(error);
throw new SystemException(error);
}
CollectorDetail collectorDetail =
new CollectorDetail(NextNumberFactory.getInstance().getNextNumberLong("cocollectordetail")
, collectorHeader
, provenanceLinkPk
, provenanceLinkClass);
collectorHeader.getCollectorDetails().add(collectorDetail); //NULLPOINTEREXCEPTION
em.merge(collectorDetail);
em.merge(collectorHeader);
return collectorDetail;
}
Sql Schema:
CREATE TABLE COCOLLECTORHEADER (
COLLECTORHEADERID DECIMAL(20,0) NOT NULL PRIMARY KEY,
COLLECTEDTIMESTAMP TIMESTAMP, -- the date when the information was collected
PROCESSEDTIMESTAMP TIMESTAMP, -- the date when the information was processed
FILEFORMAT VARCHAR(16) NOT NULL,
SEQUENCENUMBER INTEGER
);
CREATE TABLE COCOLLECTORDETAIL (
COLLECTORDETAILID DECIMAL(20,0) NOT NULL PRIMARY KEY,
COLLECTORHEADERID DECIMAL(20,0) NOT NULL
REFERENCES COCOLLECTORHEADER(COLLECTORHEADERID),
PROVENANCELINKPK DECIMAL(20,0) NOT NULL,
PROVENANCELINKCLASS VARCHAR(128) NOT NULL
);
Any assistance would be much appreciated.
Initialize collectorDetails with a valid collection object as:
private List<CollectorDetail> collectorDetails = new ArrayList<CollectorDetail>();
Also check Is it good practice to initialize fields inside a JPA entity getter?

Categories

Resources