JPA: how to override column names of #Embedded attributes - java

Person class
#Embeddable
public class Person {
#Column
public int code;
//...
}
is embedded inside Event twice as two different attributes: manager and operator
#Entity
public class Event {
#Embedded
#Column(name = "manager_code")
public Person manager;
#Embedded
#Column(name = "operator_code")
public Person operator;
//...
}
This should give two respective columns when generating database schema with Persistence. Instead an exception is thrown:
org.hibernate.MappingException: Repeated column in mapping for entity: Event column: code
How to override default column name code for each attribute?

Use #AttributeOverride, here is an example
#Embeddable public class Address {
protected String street;
protected String city;
protected String state;
#Embedded protected Zipcode zipcode;
}
#Embeddable public class Zipcode {
protected String zip;
protected String plusFour;
}
#Entity public class Customer {
#Id protected Integer id;
protected String name;
#AttributeOverrides({
#AttributeOverride(name="state",
column=#Column(name="ADDR_STATE")),
#AttributeOverride(name="zipcode.zip",
column=#Column(name="ADDR_ZIP"))
})
#Embedded protected Address address;
...
}
In your case it would look like this
#Entity
public class Event {
#Embedded
#AttributeOverride(name="code", column=#Column(name="manager_code"))
public Person manager;
#Embedded
#AttributeOverride(name="code", column=#Column(name="operator_code"))
public Person operator;
//...
}

Related

How to persist nested objects with Hibernate?

I have two classes, Customer and ShoppingCart. The java structure of the two classes is the following:
Customer class:
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public class Customer extends User implements Serializable {
#OneToOne(mappedBy = "owner", cascade=CascadeType.ALL)
private ShoppingCart shoppingCart;
#OneToMany(mappedBy = "customer", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<Purchase> purchases;
public Customer() {
super();
}
public Customer(String username, String email, String password) {
super(username, email, password);
this.shoppingCart = new ShoppingCart();
this.purchases = new ArrayList<>();
}
getters and setters
}
ShoppingCart class:
#Entity
public class ShoppingCart implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer shoppingCartId;
#OneToOne
#JoinColumn(name = "owner_id")
private Customer owner;
#OneToMany(mappedBy = "shoppingCart")
private List<CartItem> items;
public ShoppingCart(Customer owner) {
this.owner = owner;
this.items = new ArrayList<>();
}
public ShoppingCart() {
this.items = new ArrayList<>();
}
getters and setters
}
If needed, this is the User class:
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Integer userId;
private String username;
private String email;
private String password;
public User() {
}
public User(String username, String email, String password) {
this.username = username;
this.email = email;
this.password = password;
}
getters and setters
}
I have configured the Repositories classes in this way:
#Repository
public interface CustomerRepository extends CrudRepository<Customer, Integer> {
}
#Repository
public interface UserRepository extends CrudRepository<User, Integer> {
}
#Repository
public interface ShoppingCartRepository extends CrudRepository<ShoppingCart, Integer> {
}
What I want is simple, once I create a Customer, I also want to create a ShoppingCart tuple inside the database. And it actually works fine, the only problem is that the foreign key of the ShoppingCart related with the Customer is set to null. I just have the shopping_cart_id attribute set to an integer value (correctly).
The code I used to test it is the following:
Customer customer = new Customer("stefanosambruna", "ste23s#hotmail.it", "*******");
customerRepository.save(customer);
Now, I may have put some annotations in the wrong places, but I really don't know which ones. Is it related to the constructors? Or to the #JoinColumn and mappedBy configurations? I read all the Q&As about this topic here on StackOverflow and on some other sources, but I didn't find anything 100% useful. Hope to have given all the necessary details.

How to access fields of #EmbeddedId?

I have an #Entity that has a composite primary key. Therefore I created an #EmbeddedId holding the PK fields.
Question: is it better to access those fields by id.* directly, or should I create getter/setter in the parent class?
Example:
#Entity
public class MyPerson {
#EmbeddedId
private PersonId id;
public String getFirstname() {
return id.getFirstname();
}
public String getLastname() {
return id.getLastname();
}
public LocalDate getDob() {
return id.getDob();
}
}
#Embeddable
public class PersonId implements Serializable {
private String firstname;
private String lastname;
private LocalDate dob;
//getter+setter as well
}
Should I better use person.getFistname() or person.getId().getFirstname()?
The former is more clear, but with the drawback that I'd have to create the getters both in MyPerson and in PersonId.
What should be the preferred way to access, and why?
You do not have to create property
private PersonId id
Alternative is
#Entity #IdClass(PersonId.class)
public class MyPerson {
#Id private String firstname;
#Id private String lastname;
#Id private LocalDate dob;
// Getters and setters here
}
And use PersonId only for loading MyPerson entities:
PersonId peronId = new PersonId(firstname, lastname, dob);
MyPerson person = session.get(MyPerson.class, personId);

Spring JPA mapping - first steps

I have class User:
#Entity
public class User {
#Id
#GeneratedValue
private Integer id;
private String name;
private String password;
#ManyToMany
#JoinTable
private List<Role> roles;
}
Class Owner inherits from User
#Entity
public class Owner extends User {
private String pesel;
private String adress;
#OneToMany(cascade={CascadeType.PERSIST, CascadeType.REMOVE})
private List<Pet> pets;
}
and Owner had Pet
public class Pet {
#Id
#GeneratedValue
private Integer id;
private String name;
private String weight;
#ManyToOne
private Owner owner;
}
Why when starting the application gets the error:
org.springframework.data.mapping.PropertyReferenceException: No
property user found for type Pet!
--EDIT
First I have version, which was as follows:
now I try to share User instance to a doctor and the owner of the animal
The problem is that I do not know whether I am doing the mapping , and therefore wanted to ask whether it must look like
--edit2
I've simplified the scheme just a bit to better illustrate what happens
--edit3
Currently my Object's was presented:
#Entity
public class Pet {
#Id
#GeneratedValue
private Integer id;
private String name;
private String weight;
}
User
#Entity
public class User {
#Id
#GeneratedValue
private Integer id;
private String name;
private String password;
#ManyToMany
#JoinTable(name="user_roles")
private List<Role> roles;
}
PetOwner
#Entity
public class PetOwner extends User {
private String pesel;
private String adress;
#OneToMany(mappedBy="petOwner")
private List<Pet> pets;
}
I replace
#ManyToOne
private PetOwner petOwner;
for
#ManyToOne
private Owner petOwner;
and it works. Do you have a PetOwner class?
Also provide the log error to get more information about it

I cannot get One-to-one relationship and inheritance to work simultaneously in Hibernate

I am new to Hibernate and learning all the different annotations can be frustrating at times. Currently, I am stuck on making Doctor extend Person and also have a 1-to-1 relationship between Doctor and Specialty. I've been stuck on this for a while and still cannot figure this one out. I've tried testing out one of the two relationships and my code works fine, but I encounter a problem when I put everything together.
this is the error I'm getting:
Exception in thread "main" org.hibernate.MappingException: Could not
determine type for: edu.cs157b.medicalSystem.Specialty, at table:
Person, for columns: [org.hibernate.mapping.Column(specialty)]
Doctor:
package edu.cs157b.medicalSystem;
import javax.persistence.*;
#Entity
public class Doctor extends Person {
#OneToOne
#JoinColumn(name = "SPECIALTY_ID")
private Specialty specialty;
private double salary;
public void setSalary(double salary) {
this.salary = salary;
}
public double getSalary() {
return salary;
}
public void setSpecialty(Specialty specialty) {
this.specialty = specialty;
}
public Specialty getspecialty() {
return specialty;
}
}
Speciality:
package edu.cs157b.medicalSystem;
import javax.persistence.*;
#Entity
public class Specialty {
#OneToOne
private Doctor doctor;
#Id
#GeneratedValue
#Column(name = "SPECIALTY_ID")
private int sId;
private String specialtyTitle;
public void setSId(int sId) {
this.sId = sId;
}
public int getSId() {
return sId;
}
public void setSpecialtyTitle(String specialtyTitle) {
this.specialtyTitle = specialtyTitle;
}
public String getSpecialtyTitle() {
return specialtyTitle;
}
public void setDoctor(Doctor doctor) {
this.doctor = doctor;
}
public Doctor getDoctor() {
return doctor;
}
}
Person:
package edu.cs157b.medicalSystem;
import javax.persistence.*;
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Person {
private int personId;
private String first_name;
public Person() {
}
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name = "PERSON_ID")
public int getPersonId() {
return personId;
}
public void setPersonId(int personId){
this.personId = personId;
}
public void setFirstName(String first_name) {
this.first_name = first_name;
}
public String getFirstName() {
return first_name;
}
}
There are two errors in your code.
First, you annotated the getter in Person, and annotated the field in its subclass Doctor. That's why you get this error: once Hibernate sees the #Id annotation on a getter in the base class, it only considers annotations on getters in the rest of the class hierarchy, and ignores the annotations on fields.
Second, your OneToOne bidirectional association is mapped incorrectly. One side must always be the inverse side in a bidirectional association. So, the following field:
#OneToOne
private Doctor doctor;
should be
#OneToOne(mappedBy = "specialty")
private Doctor doctor;
to inform JPA that the Specialty.doctor association is the inverse side of the OneToOne association already declared and mapped in Doctor.specialty.

Hibernate: #EmbeddedId, Inheritance and #SecondaryTable

I'm using Hibernate version 3.3.2.GA with annotations.
I have inheritance between two classes, the former:
#Entity
#Table(name = "SUPER_CLASS")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(
name="DISCR_TYPE",
discriminatorType= DiscriminatorType.STRING
)
#org.hibernate.annotations.Entity(mutable = false)
public class SuperClass { }
The subclass is mapped with a secondary table:
#Entity
#DiscriminatorValue("VALUE")
#org.hibernate.annotations.Entity(mutable = false)
#SecondaryTable(name = "V_SECONDARY_TABLE",
pkJoinColumns = #PrimaryKeyJoinColumn(name = "ID", referencedColumnName = "ID"))
public class SubClass extends SuperClass {
#Embedded
public Field getField() {
return getField;
}
}
Where the field is composed of two different fields
#Embeddable
public class Field {
#Column("FIELD_1") String field1
#Column("FIELD_2") String field2
}
Now when I create a query on SubClass the FIELD_1 and FIELD_2 fields are searched on the SuperClass, even if they're defined in the subclass.
I can't set the table in the #Column annotation in the field, because the Field class it's reused somewhere. I need to specify it in SubClass class.
How do I specify that the field should be searched in the secondary table?
Also on Hibernate Forum
You should use table attribute
#Column("FIELD_1", table="V_SECONDARY_TABLE")
UPDATE
When a embeddable column is used by more than one entity, you should use #AttributeOverride if you need to re-map just a single column or #AttributeOverrides if more than one column
#Entity
#SecondaryTable(name="OTHER_PERSON")
#AttributeOverride(name="address.street", column=#Column(name="STREET", table="OTHER_PERSON"))
public class Person {
private Address address;
#Id
#GeneratedValue
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
#Embedded
public Address getAddress() { return address; }
public void setAddress(Address address) { this.address = address; }
#Embeddable
public static class Address implements Serializable {
private String address;
public String getStreet() { return street; }
public void setStreet(String street) { this.street = street; }
}
}

Categories