Zero to One (Optional One to One) Entity Relationship Issue (attempted to assign null one-to-one property) - spring-boot

Unable to update entity for optional one to one relationship using spring data jpa(2.1.2.RELEASE) and spring boot(2.1.2.RELEASE)
Getting the error attempted to assign null one-to-one property
#Entity
#Table(name = "table_a")
public class EntityA {
#Id
String id;
String aa;
int bbb;
#Nullable
#OneToOne(mappedBy = "inv", optional = true,cascade = CascadeType.ALL)
EntityB bEntity;
}
#Entity
public class EntityB{
#Id
String id;
String aaa;
String nnnn;
#OneToOne
#MapsId
#JoinColumn(name = "id")
EntityA aEntity;
}
DAO Code as below
Optional eA = entARepo.findById("1234");
EntityA entA= null;
if (eA.isPresent()) {
entA= eA.get();
}
EntityB eB = entA.getBEntity();
if (Objects.isNull(eB)) {
eB= new EntityB();
eB.setAAA("12121");
eB.setAEntity(entA);
entA.setBEntity(entB);
}
repository.save(entA);
}``

I resolved this by using a join table instead of a shared primary key approach. would still to know how to make the shared primary key approach work for optional one to one relationship

Related

#MapsId Hibernate error: attempted to assign id from null one-to-one property

I have some entities (i've left out getters/setters, and some other fields):
#Entity
public class Platform {
#Id
#GeneratedValue
private UUID id;
#OneToMany(mappedBy = "platform", cascade = CascadeType.ALL)
List<PlatformDq> platformDqs = new ArrayList<PlatformDq>();
}
#Entity
public class PlatformDq {
#EmbeddedId
private PlatformDqId platformDqId;
#ManyToOne
#MapsId("platformId")
#JoinColumn(name = "id")
private Platform platform;
}
#Embeddable
public class PlatformDqId {
#Column(name = "platform_id")
private UUID platformId;
#Column(name = "dq")
private String dq;
}
This composite primary key is platform_id and dq columns.
platform_id is also a foreign key.
I want the PlatformDq's platform_id to be generated the same time as the Platform's id.
That is, when I create a new Platform with some PlatformDqs, the composite key platform_id should have the same id as id on Platform, and the dq field is set to some value.
When I try and do it this way, hibernate tells me:
attempted to assign id from null one-to-one property
Just looking at the error it seems that Platform entity part of PlatformDq is not initialized.
Try setting the following as that will explicitly tell jpa of the relationship and further what value to populate for the platform id.
Platform p = new Platform();
//Required Setters
//for each PlatformDq
PlatformDq dq = new Platform();
//Setters
dq.setPlatform(p);

spring jpa findBy column of inside entity

I have a couple of related entities in a relational DB:
#Entity
public class A {
#Id
#Column(name = "id" ...)
private UUID id;
#OneToMany(mappedBy = "a")
private Set<B> bs;
}
and
#Entity
public class B {
#Id
#Column(name = "id" ...)
private UUID id;
#ManyToOne
#JoinColumn(name = "a_id")
private A a;
}
So I have a B Repository
#Repository
public interface BRepository extends JpaRepository<B, UUID> {
List<B> findByA(A a);
}
And id like to have a query by which I obtain the all Bs with the same A. I'm used to have an a_id column in B, not the whole entity. I don't know how to manage this, nor with a JPA query nor with a NamedQuery.
Many thanks in advance!
Luis
As already answered, the proposed code should already work but it didn't... The fix that worked for me was
List<B> findByA_Id(UUID id);
Table_Field references field field to table Table.

Why Value is not getting assigned in JPA for insert statement

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.

OneToMany relationship using non-primary composite key

I have a table structure like this
Good Assignments Entity
#Embeddable
public class GoodAssignmentId {
String clientId,
String assignmentNumber;
LocalDate effectiveDate;
// Getters and setters
}
#Entity
#IdClass(GoodAssignmentId.class)
class GoodAssignment {
#id
String clientId;
#Id
String assignmentNumber;
#Id
LocalDate effectiveDate;
#OneToMany(mappedBy = "parentKey")
Set<GoodTasks> children;
String description;
// getters and setters goes below
}
Bad Assignments Entity
#Entity
#IdClass(BadAssignmentId.class)
class BadAssignment {
#id
String clientId;
#Id
String assignementNumber;
#Id
LocalDate effectiveDate;
String description;
// Getters and setters goes below
}
Child entities
#Entity
#IdClass(ParentTasksId.class)
#DiscriminatorColumn(name = "fieldD", discriminatorType = DiscriminatorType.STRING)
class ParentTasks {
#Id
String clientId;
#Id
String assignmentNumber;
#Id
String taskNumber;
}
#Entity
#DiscriminatorValue("G")
class GoodTasks extends ParentTasks {
#ManyToOne
#JoinColumns({
#JoinColumn(name = "clientId", referencedColumName = "clientId"),
#JoinColumn(name = "assignmentNumber", referencedColumName = "assignmentNumber")
})
GoodAssignments parentKey;
other fields....
}
This shows the error referencedColumnNames(fieldA, fieldB) of .... not mapped to a single property.
Unfortunately I cannot change the table structure. TableA has 3 columns as primary key, but only two of them forms the primary key in table B along with another field (fieldD via #DiscriminatorValue used by multiple classes). How can I map this relationship to get list of TableB items in TableA?
Example Class Diagram:
Effective date in the assignments tables is not part of tasks. So this is not a perfect relationship in JPA terms. It's a legacy design which cannot be changed for some reasons.

how to add #onetoone mapping for self entity in hibernate

how to add one-to-one mapping for the self entity. Like in this example. I want to have parent-child relationship for the Person itself.
#Entity
#Table(name="PERSON")
public class Person {
#Id
#Column(name="personId")
private int id;
#OneToOne
#JoinColumn()
private Person parentPerson;
}
Here is example of bidirectional self mapping #OneToOne (I change column names to SQL notation):
#Entity
#Table(name="PERSON")
public class Person {
#Id
#Column(name="person_id")
private int id;
#OneToOne
#JoinColumn(name = "parent_person_id")
private Person parentPerson;
#OneToOne(mappedBy = "parentPerson")
private Person childPerson;
}
But, I don't understand why you want to use #OneToOne in this case.
I am using it like this:
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "PARENT_ID", nullable = true)
private Person parent;
In order to add parent from your service layer, you need to already have at least one Person in the database.
Lets presume you do. Then create a new person. For e.g.:
#Transactional
public void createPerson() {
Person parent = //get your parent
Person child = new Person();
if (parent != null) {
child.setParent(parent);
}
}
If this is what you mean..

Resources