How can I do relation between one entity, something like followers at Instagram. I did something like below, but I'm getting "D has the wrong number of column. should be 2"
How can I do relation between one type object?
#Embeddable
public class DRelationshipKey implements Serializable {
#Column(name = "d1_id")
Long d1Id;
#Column(name = "d2_id")
Long d2Id;
}
#Entity
public class DRelationship {
#EmbeddedId
public DRelationshipKey id;
#ManyToOne
#MapsId("d1Id")
private D d1;
#ManyToOne
#MapsId("d2Id")
private D d2;
#Column
String type;
}
public class D {
...
#ManyToMany
#JoinTable(name = "d_relationship",
joinColumns = #JoinColumn(name = "d1_id"),
inverseJoinColumns = #JoinColumn(name = "d2_id"))
private List<DRelationship> relatedEntities;
}
Related
I'm having problems mapping composite keys in jpa / hibernate. The parent entity and the child entity both have composite primary keys.
I have been able to use #mapsId when the parent entity has a simple key and the child has a composite key.
In the hibernate documentation they use #JoinCoumns in the mapping to demonstrate mapping two composite keys. But in their example its not clear where those column references are defined.
I have the following:
#Embeddable
public class PriceRequestLegKey implements Serializable {
#Column(name = "leg_request_id")
private String requestId;
#Column(name = "display_index")
private int displayIndex;
...
}
#Embeddable
public class AllocationKey implements Serializable {
#Column(name = "leg_request_id")
private String requestId;
#Column(name = "display_index")
private int displayIndex;
#Column(name = "allocation_index")
private int allocationIndex;
...
}
#Entity(name = "PriceRequestLeg")
public class PriceRequestLegModel {
#EmbeddedId
private PriceRequestLegKey legKey;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumns({
#JoinColumn(name = "leg_request_id", referencedColumnName = "leg_request_id"),
#JoinColumn(name = "display_index", referencedColumnName = "display_index")
})
private List<AllocationModel> allocations;
...
}
#Entity(name = "Allocation")
public class AllocationModel {
#EmbeddedId
private AllocationKey allocationKey;
#ManyToOne
#MapsId
#JoinColumns({
#JoinColumn(name = "leg_request_id", referencedColumnName = "leg_request_id"),
#JoinColumn(name = "display_index", referencedColumnName = "display_index")
})
private PriceRequestLegModel leg;
...
}
At runtime when saving it gives the follow exception:
org.springframework.orm.jpa.JpaSystemException: could not get a field value by reflection getter of com.lbg.legato.rfq.data.entity.AllocationKey.displayIndex; nested exception is org.hibernate.PropertyAccessException: could not get a field value by reflection getter of com.lbg.legato.rfq.data.entity.AllocationKey.displayIndex
Which I assume is spurious as there are getters and setters. I also get the same error if I use mappedBy="leg" on the priceRequestLegModel and #MapsId on the AllocationModel. Could anyone point out what I'm doing wrong here?
You should restore the mappedBy="leg" to the PriceRequestLegModel #OneToMany annotation:
#Entity(name = "PriceRequestLeg")
public class PriceRequestLegModel {
#EmbeddedId
private PriceRequestLegKey legKey;
#OneToMany(mappedBy="leg", cascade = CascadeType.ALL)
private List<AllocationModel> allocations;
...
}
Then you should change AllocationKey to reference PriceRequestLegKey:
#Embeddable
public class AllocationKey implements Serializable {
PriceRequestLegKey legKey; // corresponds to PK type of PriceRequestLegModel
#Column(name = "allocation_index")
private int allocationIndex;
...
}
And then set the value of the Allocation.leg #MapsId annotation appropriately:
#Entity(name = "Allocation")
public class AllocationModel {
#EmbeddedId
private AllocationKey allocationKey;
#ManyToOne
#MapsId("legKey")
#JoinColumns({
#JoinColumn(name = "leg_request_id", referencedColumnName = "leg_request_id"),
#JoinColumn(name = "display_index", referencedColumnName = "display_index")
})
private PriceRequestLegModel leg;
...
}
Some examples like this are in the JPA 2.2 spec section 2.4.1.
I have entities as below. I need to retrieve list of CIDs from CEntity using AEntity's id;
I have to traverse thru AEntity -> ABMapping -> BEntity -> fetch CID from CEntity.
Is there a way to achieve this in JPA or Should I go native query way joining all four tables and get CIDs from CEntity?
Entity A
#Entity
public class AEntity {
#Id
private long id;
#ManyToMany
#JoinTable(name = "ABMapping", joinColumns = #JoinColumn(name = "AEntity_ref", referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name = "BEntity_ref", referencedColumnName = "id"))
private List<BEntity> bEntities = new ArrayList<>();
}
Entity B
#Entity
public class BEntity {
#Id
private long id;
private CEntity cEntity;
#ManyToMany(mappedBy = "bEntities")
private List<AEntity> aEntities;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "cEntityId")
public CEntity getCEntity() {
return cEntity;
}
}
Entity ABMapping
#Entity
public class ABMapping {
#Id
private long id;
#Column(name="AEntity_ref")
private long ARefId;
#Column(name = "BEntity_ref")
private long BRefId;
}
Entity C
#Entity
public class CEntity {
#Id
private long id;
private String CID;
private List<BEntity> bEntity;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "c", cascade =
CascadeType.ALL)
public List<BEntity> getBEntities() {
return bEntity;
}
#Column(name = "CID_column")
public String getCId() {
return CID;
}
public void setCId(String CID) {
this.CID = CID;
}
}
I went with what #JB Nizet has suggested with.
select distinct c from AEntity a join a.bEntities b join b.cEntity c where a.id = :id
I am trying to map a race day that has multiple races, and can't figure out the annotations.
What I want to end up with is something like (this is a simplified example):
TABLE: race_day
date (PK)
venue (PK)
description
TABLE: race
date (PK but also FK on race_day table)
venue (PK but also FK on race_day table)
race_number (PK)
description
So far I've come up with the following POJO + annotations:
public class RaceDayPK implements Serializable {
#Column(name="race_date")
private String raceDate;
#Column(name="venue")
private String venue;
...
}
public class RaceDay {
#EmbeddedId
private RaceDayPK raceDayPk;
#OneToMany(mappedBy = "raceDay", orphanRemoval = true, cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)
private final List<Race> races = new ArrayList<>();
...
}
public class Race {
#ManyToOne
#JoinColumns({
#JoinColumn(name = "race_date", referencedColumnName = "race_date"),
#JoinColumn(name = "venue", referencedColumnName = "venue")
})
private RaceDay raceDay;
private int raceNumber;
private String raceTitle;
...
}
How do I make an EmbeddedId for Race (I'm guessing that's what I need) with both the raceDay join column AND raceNumber in it? Any help appreciated. I have seen dozens of JoinColumn examples and EmbeddedId examples here on StackOverflow but none that seem to combine the two in the way that I need.
After some hacking around, I think I got it working like this. Note the nested "racePk.raceMeeting" in the mappedBy parameter for the OneToMany annotation:
public class RaceDayPK implements Serializable {
#Column(name="race_date")
private String raceDate;
#Column(name="venue")
private String venue;
...
}
public class RaceDay {
#EmbeddedId
private RaceDayPK raceDayPk;
#OneToMany(mappedBy = "racePk.raceDay", orphanRemoval = true, cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)
private final List<Race> races = new ArrayList<>();
...
}
public class RacePk implements Serializable {
#ManyToOne
#JoinColumns({
#JoinColumn(name = "race_date", referencedColumnName = "race_date"),
#JoinColumn(name = "venue", referencedColumnName = "venue")
})
private RaceDay raceDay;
#Column(name = "race_number")
private int raceNumber;
...
}
public class Race {
#EmbeddedId
private final RacePk racePk = new RacePk();
private String raceTitle;
...
}
No idea yet whether this will fall over at some point but the MySQL tables appear to have been auto-generated correctly.
TABLE: race_day
id(PK)
date (PK)
venue (PK)
description
TABLE: race
id(PK but also FK on race_day table)
date (PK but also FK on race_day table)
venue (PK but also FK on race_day table)
race_number (PK)
description
For the above given tables, I was able to generate the sequence and get the data persisted in the tables following the constraints using the below code.
public class RaceDayPK implements Serializable {
private Long id;
private String raceDate;
private String venue;
...
}
#Entity
#IdClass(RaceDayPK.class)
public class RaceDay {
#Id
#Column(name="id")
#GeneratedValue(strategy=GenerationType.SEQUENCE,generator = "R_SEQ")
#SequenceGenerator(sequenceName = "RD_SEQ", allocationSize = 1, name = "R_SEQ")
private Long id;
#Id
#Column(name="race_date")
private String raceDate;
#Id
#Column(name="venue")
private String venue;
#OneToMany(mappedBy = "raceDay", cascade = {CascadeType.ALL}, fetch = FetchType.LAZY)
private Set<Race> races;
...
}
public class RacePK implements Serializable {
private RaceDay raceDay;
private int raceNumber;
...
}
#Entity
#IdClass(RacePK.class)
public class Race {
#Id
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumns({
#JoinColumn(name = "race_date", referencedColumnName = "race_date"),
#JoinColumn(name = "venue", referencedColumnName = "venue"),
#JoinColumn(name = "id", referencedColumnName = "id")
})
#JsonIgnore
private RaceDay raceDay;
#Id
private int raceNumber;
private String raceTitle;
...
}
the dao code needs to be changed a bit as to below.
public RaceDay saveRaceDay(RaceDay raceDay){
if(raceDay.getRaces()!=null){
raceDay.getRaces().forEach(race ->{
race.setRaceDay(raceDay);
});
}
}
Not sure if it works but try this approach:
public class RacePK implements Serializable {
private RaceDayPK raceDay;
private String raceNumber;
...
}
#Entity
#IdClass(RacePK.class)
public class Race {
#Id
#ManyToOne...
private RaceDay raceDay;
#Id
private int raceNumber;
private String raceTitle;
...
}
Note that PK field names should be exactly the same as #id-annotaed field names.
Google for Derived identifiers to learn more.
I have two class and I want to use OneToMany relation with EmbeddedId
(Im working with kundera framework)
my sensor entity class:
public class SensorEntitie implements Serializable {
#EmbeddedId
private CompoundKey key;
#Column
private float temperature;
#Column
private float pressure;
#OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
#JoinColumn(name="what I should to put here")
private List<PieceEntitie> pieces;
}
#Embeddable
public class CompoundKey
{
#Column
private String IdSensor;
#Column
private long date;
#Column(name = "event_time")
private long eventTime;
my piece class entity
public class PieceEntitie implements Serializable{
/**
*
*/
#Id
private String IdPiece;
#Column
private double width;
#Column
private double height;
#Column
private double depth;
but how can i fill the blank in #JoinColumn
I found the solution :
to use OneToMany relation with EmbeddedId, I should to declare JoinColumns and multiple of JoinColumn
#OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
#JoinColumns({
#JoinColumn(name = "idsensor", referencedColumnName = "idsensor"),
#JoinColumn(name = "date", referencedColumnName = "date"),
#JoinColumn(name = "event_time", referencedColumnName = "event_time")
})
You need to do some following steps for fixing problem
Remove #JoinColumn you dont need to write that statement
Remove #OneToMany to created object
Bind #OneToMany with getter method as per my following code
#OneToMany(mappedBy = "pieceEntitie", cascade = CascadeType.ALL,
fetch=FetchType.EAGER)
public Set<PieceEntitie> getPieceEntitie() {
return pieceEntitie;
}
I have two tables which have Many-to-Many relations which have a JoinTable USER_SERVICES as below.
#Entity
public class User implements Serializable {
#NotNull
#Column(unique=true)
private String username;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(
name = "USER_SERVICES",
joinColumns = {#JoinColumn(name = "id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "", referencedColumnName = "name")})
private Set<Services> services;
// Getters and Setters
}
#Entity
public class Services implements Serializable {
#NotNull
#GeneratedValue(strategy = GenerationType.AUTO)
#Id
private Long serviceId;
#NotNull
#Column(unique=true)
private String name;
//Getters and Setters
}
The above code creates a table USER_SERVICES, but I also want to have a Many-to-Many relation on the table USER_SERVICES with another table RATINGS which would result in another table USER_SERVICES_RATINGS. how can I define this relation with Hibernate/JPA annotations?
Bi-Directional Many to Many using user managed join table object (Relatively common)
Commonly used when you want to store extra information on the join object such as the date the relationship was created.
public class Foo{
private UUID fooId;
#OneToMany(mappedBy = "bar", cascade=CascadeType.ALL)
private List<FooBar> bars;
}
public class Bar{
private UUID barId;
#OneToMany(mappedBy = "foo", cascade=CascadeType.ALL)
private List<FooBar> foos;
}
#Entity
#Table(name="FOO_BAR")
public class FooBar{
private UUID fooBarId;
#ManyToOne
#JoinColumn(name = "fooId")
private Foo foo;
#ManyToOne
#JoinColumn(name = "barId")
private Bar bar;
//You can store other objects/fields on this table here.
}
You need to create an explicit UserServices entity and setup the relationship to the Ratings entity per your needs.
Remember that in hibernate you model relationships between entities (i.e. your java objects), not db tables.