I'm working with Spring Data JPA and I'm trying to create 4 different entities that will have exactly the same fields but they will be stored in 4 different tables.
This is my key class
public class IndexId implements Serializable {
private int seqNo;
private String index;
// getters and setters
}
Then I have the base class:
#MappedSuperclass
public class BaseIndex {
#Id
#Column(name = "seq_no", nullable = false)
protected int seqNo;
#Id
#Column(name = "index", nullable = false)
protected String index;
#Column(name = "value", nullable = false)
protected String value;
//getters/setters
}
Then my entity that will store in the database:
#Entity
#IdClass(IndexId.class)
#Table(name = "bibliographic_single_index")
public class BibliographicSingleIndex extends BaseIndex implements Serializable { }
This is the error I get: Persistent entity 'BibliographicSingleIndex' should have primary key .
I also tried with the properties declared as private and the articles I see on this subject seem to do the same thing.
With these pieces of code is it possible to identify what I'm doing wrong?
I believe every entity needs a separate java class for the id class. You wouldn't have the problem with embedded ids I think.
Related
I created the following models:
"Vendor"
"PickupStation"
And both of them have a OneToMany Relationship to a composite Key
"PickupStationVendorDetails" which has an embedded Id "PickupStationVendorKey"
It works to save the "PickupStationVendorDetails" with the corresponding Vendor and PickupStation but when I want to fetch them from e.g the Vendor nothing is found.
Vendor.java
#Entity
public class Vendor {
...
#OneToMany(mappedBy = "vendor")
private Set<PickupStationVendorDetails> pickupStations;
}
PickupStation.java
#Entity
public class PickupStation {
#OneToMany(mappedBy = "pickupStation")
private Set<PickupStationVendorDetails> vendors;
}
PickupStationVendorDetails.java
#Entity
public class PickupStationVendorDetails {
#EmbeddedId
private PickupStationVendorKey id;
#ManyToOne
#MapsId("vendorId")
#JoinColumn(name = "vendor_id")
private Vendor vendor;
#ManyToOne
#MapsId("pickupStationId")
#JoinColumn(name = "pickup_station_id")
private PickupStation pickupStation;
}
PickupStationVendorKey.java
#Embeddable
public class PickupStationVendorKey implements Serializable {
#Column(name = "vendor_id", columnDefinition = "BINARY(16)")
private UUID vendorId;
#Column(name = "pickup_station_id")
private Long pickupStationId;
public PickupStationVendorKey() {
}
public PickupStationVendorKey(UUID vendorId, Long pickupStationId) {
this.vendorId = vendorId;
this.pickupStationId = pickupStationId;
}
....
}
How I persist the entities:
At first I create the embeddedID and save the details via repository:
PickupStationVendorDetails pickupStationVendorDetails = new PickupStationVendorDetails();
pickupStationVendorDetails.setVendor(vendor);
pickupStationVendorDetails.setPickupStation(pickupStation);
pickupStationVendorDetails.setDeliveryDays(relationship.getDeliveryDays());
PickupStationVendorKey embeddedId = new PickupStationVendorKey(vendor.getId(),pickupStation.getId());
pickupStationVendorDetails.setId(embeddedId);
PickupStationVendorDetails d = pickupStationVendorDetailsRepository.save(pickupStationVendorDetails);
Afterwards I add them to the Set<> of the corresponding Entities and save them too.
vendor.getPickupStations().add(d);
pickupStation.getVendors().add(d);
vendorService.save(vendor);
pickupStationRepository.save(pickupStation);
And when I try to call vendor.getPickupStations() there seems to be no relationship.
Except I call pickupStationVendorDetailsRepository.findAll() the composite Key is correctly persisted and saved, and from there on I would be able to get the PickupStation and the Vendor. But that's not how it should work I guess.
Am I missing something?
I have main entity:
#Entity
#Table(name = "partners")
public class Partner {
#ElementCollection
#CollectionTable(
name = "external_login",
joinColumns = #JoinColumn(name = "partner_id")
)
private List<ExternalLogin> externalLogins;
...
}
And ExternalLogin is embeded entity
#Embeddable
public class ExternalLogin {
#Column(name = "type")
#Enumerated(value = EnumType.STRING)
private ExternalLoginType type;
#Column(name = "login")
private String login;
#Column(name = "password_value")
private String passwordValue;
}
public enum ExternalLoginType {
ABC;
}
#Column and #Enumerated not works in ExternalLogin entity.
For example in query will be external_login.passwordValue instead of external_login.password_value.
#Enumerated(value = EnumType.STRING) doesn't work too. Hibernate is trying to get int value of filed instead string.
Can anyone help me?
You misuse annotation #Embeddable. See description in oracle docs https://docs.oracle.com/javaee/6/api/javax/persistence/Embeddable.html
Defines a class whose instances are stored as an intrinsic part of an owning entity and share the identity of the entity. Each of the persistent properties or fields of the embedded object is mapped to the database table for the entit
#Embeddable annotation makes sense only for singular assotiation fields. Annotating list fields as #Embeddable is wrong.
Just replace
#Embeddable
public class ExternalLogin {
to
#Entity
public class ExternalLogin {
I had exactly the same issue just now.
The solution for me ended up being adding
#Access(FIELD)
To the Embeddable object.
Am having two models named Style and StyleExp with thier respective PK classes and am using JPA for mapping.
The Style class contains four variables namely pid, Sname, Screen, StyleId. and the class StyleExp has the varibales named StyleId,EId, sno,exp.
In the class Style pid, Sname, Scrn are primary keys and in the class StyleExp StyleId,EId are the primary keys. Am having one to many relation between these two classes.
I have provided the mapping like the following in Style class,
#Entity(name="Style")
#Table(name="Style")
#IdClass(StylePk.class)
public class Style implements Serializable{
#Id
private String pid;
#Id
private String Sname;
private String styleId;
.....
#OneToMany(fetch=FetchType.Lazy, mappedBy="style")
protected List<StyleExp> styleExp;
}
In the class STyleExp I have provided the Mapping as follows,
#Entity(name="StyleExp")
#Table(name="StyleExp")
public class StyleExp implements Serializable{
#Id
private String styleId;
#Id
private String eId;
#ManyToOne(fetch=FetchType.Lazy)
#JoinColumns({
#JoinColumn(name="styleId",
referencedColumnName="styleId",insertable=false,updatable=false)
})
protected Style style;
}
But when Am running these code as getting the List of StyleExp from Style class as
Style style = styleDao.getStyle(pid, Sname, Scrn)
List<StyleExp> styleExpList = style.getStyleExp();
It throws the following error
causedBy : org.hibernate.AnnotationException: referencedColumnName(styleId) of StyleExp.style referencing model.Style not mapped to a single property
So please kindly let me know what mistake am doing? and one more doubt for me is non primary key and primary key OneToMany and ManyToOne mapping is possible in JPa?
Because of the non primary key mapped to primary key is the problem in the above situation?
Kindly help me.
Thanks in Advance.
I have tried by the following for OneToMany mapping between Style and StyleExp
#Entity(name="Style")
#Table(name="Style")
public class Style implements Serializable{
private String pid;
private String Sname;
#Id
private String styleId;
.....
#OneToMany(fetch=FetchType.Lazy, cascade=CascadeType.ALL)
#JoinColumns({
#JoinColumn(name="styleId", referencedColumnName="styleId" insertable=false, updatable=false)
})
protected List<StyleExp> styleExp;
}
In the class StyleExp I have provided the Mapping as follows,
#Entity(name="StyleExp")
#Table(name="StyleExp")
public class StyleExp implements Serializable{
#Id
private String styleId;
#Id
private String eId;
}
By using the above code I can map the above two tables
You should only use #Id for primary key in your parent class Style.
Other columns that you want to set it as unique, then doing as below:
// primary key
#Id
#Column(name = "pid", unique = true, nullable = false)
private String pid;
// unique key
#Column(name = "styleId", unique = true, nullable = false)
private String styleId;
Then in your StyleExp class, you can map to the unique column styleId in Style class as below
// you are referencing to unique column in parent table
#ManyToOne
#JoinColumn(name = "styleId", nullable = false, referencedColumnName = "styleId")
protected Style style;
The "referencedColumnName" is used when you want to map to a none primary column in parent table.
Anyway, no need to use multiple #Id in a table/model class.
I've ran into problem with composite primary key handling by Hibernate as a JPA provider.
My entities look like below
// Entity class
#Entity
#IdClass(ExternalMatchPK.class)
#Table(name = "external_match")
public class ExternalMatch {
#Id
#Column(name = "place_id")
private Integer placeId;
#Id
#Column(name = "external_object_id")
private Integer externalObjectId;
// ... Other stuff here
}
// Key class
public class ExternalMatchPK implements Serializable {
private Integer placeId;
private Integer externalObjectId;
}
Looks pretty simple yet no matter what I do I keep getting the following exception (lines are splitted for readability):
org.hibernate.MappingException:
Repeated column in mapping for entity: ExternalMatch
column: external_object_id (should be mapped with insert="false" update="false")
I've tried placing annotation on entity class fields and key class fields together as well as separately, moving all annotations from fields to getters on each one of the classes, using key calss as #Embeddable and putting it into the entity class with #EmbeddedId. Nothing seems to work.
This case seems trivial so maybe it's something wrong with our setup but I can't even imagine where to look for the issue.
Any advice is much appreciated.
It appears that I shot myself in the foot with this.
The issue was that I had a biderectional mapping between ExternalMatch and ExternalObject I forgot about trying to replace the actual entity with its integer id.
So changing
// Entity class
#Entity
#IdClass(ExternalMatchPK.class)
#Table(name = "external_match")
public class ExternalMatch {
#Id
#Column(name = "place_id")
private Integer placeId;
#Id
#Column(name = "external_object_id")
private Integer externalObjectId;
// ... Other stuff here
}
// Key class
public class ExternalMatchPK implements Serializable {
private Integer placeId;
private Integer externalObjectId;
}
// Related entity class
#Entity
#Table(name = "external_object")
public class ExternalObject extends AbstractNameableEntity {
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "external_object_id", nullable = false)
private List<ExternalMatch> matches;
// ...
}
to reprsent actual mappings like this
// Entity class
#Entity
#IdClass(ExternalMatchPK.class)
#Table(name = "external_match")
public class ExternalMatch {
#Id
#ManyToOne
#JoinColumn(name = "external_object_id", referencedColumnName = "id")
private ExternalObject externalObject;
#Id
#ManyToOne
#JoinColumn(name = "place_id")
private Poi place;
// ... Other stuff here
}
// Key class
public class ExternalMatchPK implements Serializable {
private Poi place;
private ExternalObject externalObject;
}
// Related entity class
#Entity
#Table(name = "external_object")
public class ExternalObject extends AbstractNameableEntity {
#OneToMany(cascade = CascadeType.ALL, mappedBy = "externalObject")
private List<ExternalMatch> matches;
// ...
}
resolved the repeated mapping issue yet leaving us with all the familiar troubles a biderectional mapping creates :)
I got these 2 entities:
#javax.persistence.Entity
public class Book {
#javax.persistence.EmbeddedId
private BookPK id;
private String title;
#javax.persistence.ManyToOne(fetch = javax.persistence.FetchType.LAZY)
#javax.persistence.JoinColumns({
#javax.persistence.JoinColumn(name = "LNGCOD", referencedColumnName = "LNGCOD"),
#javax.persistence.JoinColumn(name = "LIBCOD", referencedColumnName = "LIBCOD") })
private Language language;
}
#javax.persistence.Entity
public class Language {
#javax.persistence.EmbeddedId
private LanguagePK id;
private String name;
}
with composed PK's:
#Embeddable
public class BookPK implements Serializable {
private Integer bookcod;
private Integer libcod;
}
#Embeddable
public class LanguagePK implements Serializable {
private Integer lngcod;
private Integer libcod;
}
If I try to create a new Book and persist it, I get an exception telling me libcod is found twice in the insert statement ("Column 'libcod' specified twice"). But I can't use "insertable = false" when defining the JoinColumn ("Mixing insertable and non insertable columns in a property is not allowed").
Is there any way to define these objects + relationship so the columns are managed automatically by Hibernate ? (I am especially thinking of libcod).
Thank you.
Create a third property "Integer libcod;" on the Book. Have that property manage the db state of libcod. Use insertable=false,updatable=false for both properties in the join to Language. in your "setLanguage" set the private libcod = language.libcod. don't expose a getter/setter for the private libcod.
Are any of the values generated at insert time? This could complicate things further, I suppose.