How to set foreign key nullable - java

I have a class configuration something like the following(just a sample not actual meaning) -
public class payment
{
#Id
#Column("payment_id")
private int paymentId;
#ManyToOne
#JoinColumn(name ="")
private Fine fine;
//getter setter and other stuff
}
public class Fine{
#Id
#Column("fine_id")
private int fineId;
#Column("amount")
private int fineAmount;
//other stuff
}
I am getting org.hibernate.ObjectNotFoundException: No row with the given identifier exists error message. In accordance with the answer it is because a foreign key cannot have null value but my db contains null. I cant change the db or project structure so is there any way so that i can issue null value to my foreign key 'legally' ie without creating an exception.

Using #Column(nulable = true)
Is used for creation of DDL scripts and does not bring the desired behavior.
You need to mark the #ManyToOne as optional.
#ManyToOne(optional = true)

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.

Hibernate JPA, one to one relationship with a composite key and a constant value

I'm attempting to implement a limited type of object level ACL and its lead me to a place where I'm attempting to create a #OneToOne relationship using a composite key with a constant and dynamic value.
I have an Entity with a database id and a constant value defined in the class.
public class Entity{
private static final int objectType = 1;
#Id
Integer id;
}
I have an access_levels table with a composite key of objectId and objectType.
public class AccessLevel {
#EmbeddedId
private AccessLevelKey accessLevelKey;
#Embeddable
class AccessLevelKey implements Serializable{
private Integer objectType;
private Integer objectId;
....
}
}
Schema of access_levels
CREATE TABLE access_levels(
object_type INTEGER NOT NULL,
object_id INTEGER NOT NULL,
....
CONSTRAINT access_levels_type_id PRIMARY KEY (object_type, object_id)
);
I'm attempting to come up with a one to one relationship that Entity can use to fetch and update its associated AccessLevel
After taking a look a the docs on Non-Standard Joins it seems like I need something like this,
Inside of Entity:
#OneToOne
#JoinColumns({
#JoinColumn(name = "id", referencedColumnName = "object_id"),
#JoinColumn(name = "access_levels.object_type", referencedColumnName = "1"),
})
private AccessLevel accessLevel;
However this throws a hibernate MappingException at app launch
Caused by: org.hibernate.MappingException: Unable to find column with logical name: 1 in access_levels
Thanks!

Why in this Hibernate mapping it is used #ManyToOne instead #OneToOne?

I am absolutly new in Hibernate development and I have the following problem.
I have 2 entity classes that maps 2 DB tables:
1) The first entity class (the main one) is named KM_ProjectInfo and map a DB table named KM_PROJECT.
2) The second entity class is named KM_ProjectInfoStatus and map a DB table named KM_PROJECT_INFO_STATUS.
So the second one represent a specific field of the first one (a status of the row representd by an instance of the KM_ProjectInfo class). Infact I have something like this:
1) KM_ProjectInfo class:
#Entity
#Table(name = "KM_PROJECT")
public class KM_ProjectInfo implements Serializable {
#Id
#GeneratedValue
private Long idProjectInfo;
#Column(name = "name")
private String name;
#Column(name = "technology")
private String technology;
#ManyToOne
#JoinColumn(name = "idCountry")
private KMCountry country;
#Column(name = "power")
private long power;
#Column(name = "cod")
private String cod;
#ManyToOne
#JoinColumn(name = "idProjectInfoStatus")
private KM_ProjectInfoStatus status;
// GETTERS & SETTERS
}
2) KM_ProjectInfoStatus:
#Entity
#Table(name = "KM_PROJECT_INFO_STATUS")
public class KM_ProjectInfoStatus implements Serializable {
#Id
#GeneratedValue
private Long idProjectInfoStatus;
#Column(name = "foldertech")
private Long foldertech;
#Column(name = "folderproject")
private Long folderproject;
// GETTERS & SETTERS
}
So, as you can see in the previous snippet, the KM_ProjectInfoStatuss is a field of the KM_ProjectInfo because I want that it contains the primary key of this table as foreign key.
In the logic of my application I want that at one row of the KM_PROJECT table (so at one instance of the KM_ProjectInfo entity class) is associated a single row of the KM_PROJECT_INFO_STATUS (one instance of the KM_ProjectInfoStatus entity class) because it represent a specific status for the KM_PROJECT row.
In my code I have:
#ManyToOne
#JoinColumn(name = "idProjectInfoStatus")
private KM_ProjectInfoStatus status;
but I think that is wrong because at one row of my first table it is associated a specific single row of the second table. But maybe I am missing something about how Hibernate work.
Can you help me to understand what I am missing? What it work? Why I have #ManyToOne instead #OneToOne?
Tnx
It all depends on how you want to model things. In terms of Database structure, OneToOne and ManyToOne are implemented in the same way:
One or more JoinColumns which makes a foreign key pointing to the primary key of the other table.
So both solutions correctly map to your database, but it depends if you want to allow several KM_ProjectInfo to point to the same KM_ProjectInfoStatus, or only allow a single one.
Note that, even though you would declare a OneToOne, you could still end up with multiple KM_ProjectInfo pointing to the same KM_ProjectInfoStatus if you don't manipulate Hibernate properly.
Here you did not declare the reverse relationship, but if you did, the declaration would have to be different:
In case of a OneToOne, you would have a KM_ProjectInfo member
In case of a OneToMany (reverse of ManyToOne), you would have a Collection<KM_ProjectInfo> member
From the description it seems you want to have one-to-one relationship. That is the project entity should have its very own status not shared by any other project. You could achieve this by using #OneToOne as below.
#Entity
#Table(name = "KM_PROJECT")
public class KM_ProjectInfo implements Serializable {
#Id
#GeneratedValue
private Long idProjectInfo;
#OneToOne
#JoinColumn(name = "idProjectInfoStatus")
private KM_ProjectInfoStatus status;
}
#Entity
#Table(name = "KM_PROJECT_INFO_STATUS")
public class KM_ProjectInfoStatus implements Serializable {
#Id
#GeneratedValue
private Long idProjectInfoStatus;
#OneToOne(mappedBy="idProjectInfoStatus")
private KM_ProjectInfo project;
}
This way you can have specific status for the KM_PROJECT.
Coming back to #ManyToOne, you will want to have this if you want to share the same status with multiple projects, but that's not what you want in your case. I have tried to explain mappings in simple way here One-to-One mapping.

#GeneratedValue in Oracle with no Sequence

I have created a trigger so that my entities ids are autogenerated with a sequence each time they're inserted into my Oracle database.
The problem comes with annotating these entities for Hibernate/JPA: I need to define a #GeneratedValue annotation but I don't want to specify the sequence name -- doing that will make Hibernate query the sequence first, then insert, which is a work that is already done by the trigger.
Is there any way to skip this sequence in the #GeneratedValue with the scenario I've proposed?
Exception I get if id is not provided:
org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): Pattern
Pattern class:
#Entity
#Table(name = "PATTERN")
public class Patron extends HistoricoAbstractEntity {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#Column(name = "ID_PATTERN")
private Integer idPattern;
#Column
private String description;
#Column(name = "NEGATIVE")
private Boolean isNegative;
#Column(name = "type")
private Integer type;
#Column(name = "N_DAYS")
private Integer numDays;
... (getters & setters)
}
From what your code,
What I can tell you is that its not related to #GeneratedValue, it specifies that the hibernate takes responsibility to generate and idetifier for your entity. In your case your are generating id your self, so you have to manually set the id for that particular entity. Then you won't get this error any more, the other thing that you can try is use of #PrePersist annotate a method with this and try assigning a value to id in it. I haven't tried this but this should work according to this answer on SO.
Assign Custom Identifier
If your id is being generated by the database then you should use #GeneratedValue(strategy=GenerationType.AUTO) on your id field along with your #Id annotation.

JPA insert foreign key as null

I have 2 entities that one of them is the foreign key of the other:
#Entity
#Table(name = "XXXX")
#XmlRootElement
public class Drfacopt implements Serializable {
#Id
#NotNull
#Basic(optional = false)
#Column(name = "OPCOD")
private Short optionCode;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 50)
#Column(name = "OPCODDH")
private String optionCodeDescription;
}
#Entity
#Table(name = "YYYY")
#XmlRootElement
public class Drfac03f implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
protected Drfac03fPK drfac03fPK;
#JoinColumn(name = "F3OPT", referencedColumnName = "OPCOD" )
#ManyToOne(optional = false)
private Drfacopt relationCode;
}
when I'm trying to insert a new record using em.persist(drfac03f) I get this exception:
During synchronization a new object was found through a relationship that was not marked cascade PERSIST
How can I insert the foreign key as null? I want to have the #Null for so when the user inserts a record directly to Drfacopt it wont be null or zero, but if it's through Drfac03f then it can be inserted as null. how can this be done?
When you try em.persist(myObj) and get the error:
During synchronization a new object was found through a relationship that was not marked cascade PERSIST
It means the object (myObj) you are trying to persist has a field/property (say foreignProperty) that has a [foreign key] relationship with myObj and neither foreignProperty was persisted before myObj, nor the relationship was marked with CascadeType.PERSIST, that is, foreignProperty does not exist in the database yet.
The solution is to persist the foreignProperty before or, as said, set the relationship CascadeType.PERSIST.
How can I insert the foreign key as null?
Since you want to set the foreign field as null, you shouldn't persist it before (there's no need to "persist" a null object).
So, just simply set the field as null and proceed to persist myObj as usual.
I tried to persist, but got the error "Null values not allowed in column or variable ..."
This error message states that you are trying to persist a null value somewhere you couldn't. There are some possible reasons:
Most probably the actual column in the database is NOT NULL. Solution: Set it to NULL.
The relationship is marked as (optional = false). The solution would be to set that optional attribute as true or remove it altogether. (Note: this is possibly implementation dependent so it requires confirmation.)

Categories

Resources