Storing enum in separate table - jpa

I have entity Student and it has field like enum City. I know how to store enums in jpa via #Enumerated annotation, but I want to store enum in separate table and have foreign key from Student to City. But I have no idea how to implement.
City
public enum City {
PAVLOGRAD("Pavlograd")
,DNEPR("Dnepr");
private String shortName;
City(String shortName) {
this.shortName = shortName;
}
public String getShortName() {
return shortName;
}
}
Student
public class Student implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Enumerated(EnumType.ORDINAL)
private City city;
}

Related

JPA how to set foreign id - in Embeddable id - that is generated

My use case is: I have a Product with multi language name. To have at most one name per language a translation should be identified by locale + productId.
My problem is to get it working with a generated productId. This are the entities:
e.g. in oracle i get: "ORA-01400: cannot insert null into ."PRODUCT_NAME"."FOREIGN_ID""
Product:
#Entity
#Data
public class Product {
#Id
#GeneratedValue
private Long id;
#Column(unique = true)
private String articleNumber;
/**
* Localized name of the product.
*/
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#MapKey(name = "nameId.locale")
private Map<Locale, ProductName> names = new HashMap<>();
}
ProductName:
#Entity
#Data
public class ProductName {
#EmbeddedId
private TranslationId nameId;
private String name;
}
TranslationId:
#Embeddable
#Data
public class TranslationId implements Serializable {
private static final long serialVersionUID = 3709634245257481449L;
#Convert(converter = LocaleConverter.class)
private Locale locale;
private Long foreignId; //<-- this is null, should reference product
}
Is there a way to get this working without having to save the product first without the name? Without a generated id it is working of course - i just set same id for both.
I would like to re-use the translation id for other translated fields of other entities.

How do I specify a JPA ManyToOne relationship based on the id being another property

If I have an entity, say, ExchangeRate, with an id of currencyCode
#Entity
public class ExchangeRate {
#Id
private String currencyCode;
private double rate;
}
and I have, say, a Price object that has a currencyCode property
#Entity
public class Price {
#Id
private String priceId;
private String supplierCurrencyCode;
private BigDecimal price; // In Supplier Currency;
#ManyToOne(fetch=FetchType.LAZY)
// where do I specify that the exchangeRate is joined using the
// supplierCurrencyCode property?
private ExchangeRate exchangeRate
public BigDecimal getPriceInLocalCurrrency() {
BigDecimal rate = BigDecimal.valueOf(exchangeRate.rate);
return price.multiply(rate);
}
}
Assuming the foreign key columns name is supplier_currency_code
#Entity
public class Price {
#Id
private String priceId;
// Must be read-only because this column is written by the ManyToOne mapping
#Column(insertable=false, updatable=false)
private String supplierCurrencyCode;
private BigDecimal price; // In Supplier Currency;
#JoinColumn(name="supplier_currency_code")
#ManyToOne(fetch=FetchType.LAZY)
private ExchangeRate exchangeRate
public BigDecimal getPriceInLocalCurrrency() {
BigDecimal rate = BigDecimal.valueOf(exchangeRate.rate);
return price.multiply(rate);
}
}

Spring JPA using primary key within #Embeddable class

In my application i have a scenario to fetch data from entity based on give input code and date.
The combination of code and date will be unique and will return a single record.
Below is my entity
class JpaEntity
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private id ;
private String code;
private Date date;
private title;
//Getters and Setters
}
I have tried below approcah by changing the entity.
class JpaEntity
{
private String title;
//Getters and setters
#EmbededId
private EntityId entityID
#Embedable
public static class EntityId implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private id ;
private String code;
private Date date;
//Getters and Setters
}
}
I am using the entity to search based on code and date
public interface PersistentDAO extends JpaRepository<JpaEntity,String> {
{
#Query("SELECT cal FROM JpaCalendar cal" + " WHERE cal.calendarId.currencyCode=:currencyCode "
+ " AND cal.calendarId.date=:date")
Optional<JpaCalendar> findById(String currencyCode, Date date);
JpaEntity findByID(String code,Date date)
}
But the JPA is throwing error saying Component Id is not found.
is it mandatory all the field in #Embedable are primary?
is it possible #Embedable class (composite id) contain the both primary and non-primay keys.
Since i am not supposed to change the structure of the table is there any way to achieve following:
Fetch record based on give code and date.
Insert new record where in id the primary key should be auto incremented
Please suggest.
Use #Embedded & #Embeddable and don't use static class inside class
class JpaEntity
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private id ;
#Embedded
private CodeDate codeDate;
private title;
}
#Embeddable
class CodeDate {
private String code;
private Date date;
}
You can use Jpa method naming query and create a CodeDate object call like this
public interface PersistentDAO extends JpaRepository<JpaEntity,String> {
{
JpaEntity findByCodeDate(CodeDate codeDate);
}

Find an entity which use a class Id

To find an object from entity with primary key we use em.find(Person.class, <Id>).
I'm using JPA EclipseLink and I have a Person entity which has a composite primary key(#classId),
the Person entity:
#Entity
#IdClass(PersonId.class)
public class Person {
#Id
private int id;
#Id
private String name;
public String getName() {
return name;
}
// getters & setters
}
and the PersonID:
public class PersonId implements Serializable {
private static final long idVersionUID = 343L;
private int id;
private String name;
// must have a default construcot
public PersonId() {
}
public PersonId(int id, String name) {
this.id = id;
this.name = name;
}
//getters & setters
//hachCode & equals
}
How to use em.find to get a Person object?
I found the solution :
PersonId personeId = new PersonId(33, "Jhon");
Person persistedPerson = em.find(Person.class, personeId);
System.out.println(persistedPerson.getID() + " - " + persistedPerson.getName());

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();
}
}