JPA reusing code by extending without inheritance - jpa

I have two or more tables resembles each other.
PARENT
ID | PK
NAME | VARCHAR
CHILD
ID |PK
NAME | VARCHAR
AGE | INT
It's not #Inheritance situation because they are independent entities and related to each other by #OneToMany or #ManyToOne.
I create entity class for each other.
#Entity
public class Parent {
#Id
private Long id;
private String name;
#ManyToOne(mappedBy = "parent")
private Collection<Child> children;
}
#Entity
public class Child {
#Id
private Long id;
private String name;
private int age;
#OneToMany
private Parent parent;
}
Is there any nice way to share common fields mappings?
// #MappedSuperclass // is this what it is exactly for?
public abstract class Base {
// #Id protected Long id; // ##?
#Column(name = "name", nullable = false)
private String name;
}
#Entity
public class Parent extends Base {
#Id
#TableGenerator(...)
#GeneratedValue(...)
protected Long id;
#ManyToOne(mappedBy = "parent")
private Collection<Child> children;
}
#Entity
public class Child extends Base {
#Id
#TableGenerator(...)
#GeneratedValue(...)
protected Long id;
private int age;
#OneToMany
private Parent parent;
}
Is this OK?
Is it even possible declaring #Id protected Long id; on the Base leaving #TableGenerator and #GeneratedVAlue on extended classes?

Is there any nice way to share common fields mappings?
MappedSuperclass is exactly right tool for that.
Is it even possible declaring #Id protected Long id; on the Base
leaving #TableGenerator and #GeneratedVAlue on extended classes?
No, it is not possible.

Related

#OneToOne Composite Primary Key of Entities

I need help for this case.
I have the following entities (I removed getters/setters/hash/toString for easy reading):
#Entity
public class Company implements Serializable{
#Id
private String id;
}
#Entity
public class Document implements Serializable{
#Id
private String id;
}
#Entity
#IdClass(Inbox.PK.class)
public class Inbox implements Serializable {
#Id
#ManyToOne(fetch = FetchType.LAZY)
private Company company;
#Id
#ManyToOne(fetch = FetchType.LAZY)
private Document document;
#OneToOne(fetch = FetchType.LAZY, mappedBy = "inbox")
private Invoice invoice;
public class PK implements Serializable{
private Company company;
private Document document;
}
}
First question is, should I use Company and Document types in PK class or String and String?
And here ... the headache :
#Entity
#IdClass(Invoice.PK.class)
public class Invoice implements Serializable {
#Id
#OneToOne(fetch = FetchType.LAZY, mappedBy = "invoice")
// #MapsId // ???
#JoinColumn(name = "companyId")//, referencedColumnName = "company")// ???
#JoinColumn(name = "documentId")//, referencedColumnName = "document")// ???
// #PrimaryKeyJoinColumn // ????
private Inbox inbox;
#Data
public static class PK implements Serializable {
// private Inbox inbox; // ???
// private String company,document; // ???
// private String companyId,documentId; // ???
// private String inboxCompanyId,inboxDocumentId; // ???
}
}
The PK of the Invoice Entity is also the FK to Inbox (I would like constraints to be generated), and the PK of Inbox is composed of two Entities (Company and Document).
I prefer to use IdClass rather EmbeddedId.
How could I configure Invoice to have, at the end, (company_id,document_id) as PK AND FK to Inbox?
I saw your question posted in upwork. I think you should use string + string type fields with #Id and #Column annotations in PK class.

Query for joins in Spring JPA

I have the below entities
#Entity
#Getter
#Setter
public class Aggregate {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToMany(mappedBy = "aggregate")
private Set<Single> singleSet;
}
#Entity
#Getter
#Setter
public class Single {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private String id;
private Integer number;
#ManyToOne
#JoinColumn(name = "agg_id")
private Aggregate aggregate;
}
I also have the below repository
public interface AggregateRepo extends CrudRepository<Aggregate, Long> {
}
I want to return all associated Single records where number in object Single is equal to some random number
I am assuming that the query will be something like this
public interface AggregateRepo extends CrudRepository<Aggregate, Long> {
public List<Single> findBySingleSet_Number(Integer number);
}
However when I try to use Intellij to complete my named query it always populates like this
public interface AggregateRepo extends CrudRepository<Aggregate, Long> {
public List<Single> findBySingleSet_Empty_Number(Integer number);
}
I am wondering what the Empty stands for ?
Also should I create another Single repository since the query is related to returning Single records.

JPA : Entity extend with entity

How can I extend an entity with another entity but both of them referring to the same table ? Is it possible ? The structure is something like this :
#Entity
#Table(name = "users")
#NamedQuery(name="User.findAll", query="SELECT u FROM User u")
public class User implements Serializable{
private int id;
private String name;
}
#Entity
#Table(name = "users")
#NamedQuery(name="SubUser.findAll", query="SELECT su FROM SubUser su")
public class SubUser extends User {
#Override
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
public int getId() {
return super.getId();
}
//- Other fields and getter setter
}
I tried this way Extend JPA entity to add attributes and logic
but I got this exception
org.hibernate.mapping.SingleTableSubclass cannot be cast to org.hibernate.mapping.RootClass
Update 1
I already put the #Id for the SubUser because the #Entity shows this exception
The entity has no primary key attribute defined
Add the #Inheritance annotation to the super class
Implement Serializable
Add a getter for id (you don't need a setter necessarily)
id should be Integer, not int, so that you can represent unassigned ids with null.
Code:
#Entity
#Table(name = "users")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
#Entity
public class SubUser extends User {
}
Any basic JPA docs would describe inheritance, discriminators and use of #Id.
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="DISCRIM", discriminatorType=DiscriminatorType.STRING)
#DiscriminatorValue("User")
#Table(name="users")
#NamedQuery(name="User.findAll", query="SELECT u FROM User u")
public class User implements Serializable{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String name;
}
#Entity
#DiscriminatorValue("SubUser")
#NamedQuery(name="SubUser.findAll", query="SELECT su FROM SubUser su")
public class SubUser extends User {
}

How to handle compound key with relationship in JPA2 and Spring Data JPA?

I have a problem to handle mapping object relationship for mysql tables.
I have 2 tables shown below:
Device
-----------
deviceId PK
deviceName
ApkInfo
--------
id PK
packageName
appName
deviceId FK
And then here are my classes:
#Entity
#Table(name="Device")
public class Device implements Serializable {
#Column
#Id
private String deviceId;
#Column
private String deviceName;
//getters and setters
}
#Entity
#Table(name="ApkInfos")
public class ApkInfo implements Serializable {
#Column
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
#Column
#Id
private String packageName;
#Column
private String appName;
#Column
#Temporal(TemporalType.TIMSTAMP)
private Date installDate;
#ManyToOne
#JoinColumn(name="deviceId" referencedColumnName="deviceId")
private Device device;
//getters and setters
}
This works for me, but I want to use compound key, deviceId and packageName, in ApkInfos table.
#Entity
#Table(name="ApkInfos")
public class ApkInfo implements Serializable {
#Colum(instable=false, updatable=false)
#Id
private String deviceId;
#Column
private String packageName;
#Column
private String appName;
#ManyToOne
#JoinColumn(name="deviceId" referencedColumnName="deviceId")
private Device device;
//getters and setters
}
But when I tried to save an entity using Spring Data JPA repository, I got an error:
org.springframework.dao.InvalidAccessApiUsageException: Class must not
be null, nested exception is java.lang.IllegalArgumentException: Class
must not be null
ApkInfo apkInfo = new ApkInfo();
apkInfo.setDeviceId("1234");
apkInfo.setPackageName("aaa");
apkInfo.setAppName("myapp");
apkInfo.setInstallDate(new Date());
apkInfo.setDevice(new Device("1234"));
repository.save(apkInfo);
And device has the deviceID '1234' already exists in the Device table.
I created a separate primary key class added #IdClass in the ApkInfo class. It works fine now, thanks. I am going to have a look at EmbeddedId more later.
I added #IdClass at the entity class and #Id for the packageName property. Also I made insert, update false for the One-to-many column.
#Entity
#Table(name="ApkInfos")
#IdClass(ApkInfo.class)
public class ApkInfo implements Serializable {
#Column #Id private String deviceId;
#Column #Id private String packageName;
#ManyToOne
#JoinColumn(name="deviceId" referencedColumnName="deviceId", insetable=false, updatable=false)
private Device device;
//getters and setters missing
}
Primary key class has only setters and overrides equals and hasCode methods.
public class ApkInfo implements Serializable {
private String deviceId;
private String packageName;
public ApkInfo(){}
public ApkInfo (String deviceId, String packageName){
this.deviceId = deviceId;
this.packageName = packageName;
}
public String getDeviceId(){
return this.deviceId;
}
public String getPackageName(){
return this.packageName;
}
#Override
public boolean equals(Object obj){
return (obj!=null &&
obj instanceof ApkInfoPk &&
deviceId.equals(((ApkInfoPk)obj).getDeviceId()) &&
packageNames.equals(((ApkInfoPk)obj).getPackageName()) );
}
#Override
public int hashCode(){
super.hashCode();
}
}

Mapping JPA entity relationships

I would like some advice on how to best layout my JPA entity classes. Suppose I have 2 tables I would like to model as entities, user and role.
Create Table users(user_id primary key,
role_id integer not null )
Create table role(role_id primary key,
description text,
)
I create the following two JPA Entities:
#Entity
#Table(name="users")
#Access(AccessType.PROPERTY)
public class User implements Serializable {
private Long userId;
private Long roleId;
private Role role;
#Column(name = "user_id")
#Id
public Long getUserId() {}
#Column(name = "role_id")
public Long getRoleId() {}
#ManyToOne()
JoinColumn(name="role_id")
public Role getRole() {}
}
Role Entity:
#Entity
#Table(name="Role")
#Access(AccessType.PROPERTY)
public class Role implements Serializable {
private String description;
private Long roleId;
#Column(name = "role_id")
#Id
public Long getRoleId() {}
#Column(name = "description")
public Long getDescrition(){}
#ManyToOne()
#JoinColumn(name="role_id")
public Role getRole() {}
}
Would the correct way to model this relationship be as above, or would I drop the private Long roleId; in Users? Any advice welcomed.
When I map it this way, I receive the following error:
org.hibernate.MappingException: Repeated column in mapping for entity:
Yes, you would drop the private Long roleId mapping when you have a #ManyToOne on the same column.
As the error implies, you can only map each column in an #Entity once. Since role_id is the #JoinColumn for the #ManyToOne reference, you cannot also map it as a property.
You can, however, add a convenience method to return the role ID, like
public Long getRoleId() {
return role.getId();
}