How to access fields of #EmbeddedId? - java

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

Related

Is it correct to use transient to return values derived from entity attributes?

Do you think it's a good code pattern to use transient in the entity to return values derived from other attributes of the entity or is there a pattern and better way to do it? Putting in the service for example?
For example:
#Entity
public class User {
#Id
private Long id;
#Column
private String firstName;
#Column
private String lastName;
#Transient
public String getFullName() {
return firstName + lastName;
}
}

Hibernate : for a single table group attributes into a subclass

I want to do :
create table user (
id bigint primary key auto_increment,
firstname varchar(128),
lastname varchar(128),
street varchar(128),
zipcode mediumint,
city varchar(128)
)
then :
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstname;
private String lastname;
private Address address; // Here I want an Address rather than street, zip, and city directly inside User
...
}
and :
public class Address {
private String street;
private Integer zipcode;
private String city;
...
}
(that is an example)
How to do that with Hibernate ? #OneToOne ? The problem seems simple and since I can't find the solution around here, it must be obvious.
First, annotate your Address class with #Embeddable:
#Embeddable
public class Address {
/*class definition here*/
...
}
And then update your user class in this way:
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstname;
private String lastname;
#Embedded
private Address address;
...
}
That's it. If you want a more complex example look here. Just pay attention to model classes definition, it makes no difference if you are using Spring Boot or not as long as you handle your database with JPA.
You can associate entities through a one-to-one relationship using #OneToOne annotation.
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Address address;
#OneToOne(cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn
public Address getAddress()
{
return address;
}
}
Reference:
https://docs.jboss.org/hibernate/annotations/3.5/reference/en/html/entity.html#entity-mapping-association

Hibernate one-to-many relationship java.sql.SQLIntegrityConstraintViolationException: Column 'person_id' cannot be null

I'm new to hibernate, learn doc save persistent object
followed hibernate doc this is person and phone relationship one-to-many
#Entity
#Table(name = "phone")
public class Phone {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "number")
private String number;
#ManyToOne(fetch = FetchType.LAZY)
private Person person;
//omit setter and getter
}
#Entity
#Table(name = "person")
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String username;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "person")
private List<Phone> phones = new ArrayList<>();
//omit getter and setter
}
I'm persistent person and add one phone the error be throw
#Test
public void say() {
Person person = new Person();
person.setUsername("aaaa");
Phone phone = new Phone();
phone.setNumber("111");
person.getPhones().add(phone);
personService.save(person);
}
this is Dao persistent
public class PersonDaoImpl implements PersonDao {
#PersistenceContext
private EntityManager entityManager;
#Override
public void save(Person person) {
entityManager.persist(person);
}
Update service code, service just save person
#Service(value = "personService")
public class PersonServiceImpl implements PersonService {
#Autowired
private PersonDao personDao;
#Transactional
#Override
public void save(Person person) {
personDao.save(person);
}
}
error info:
23:35:47.059 [main] DEBUG org.hibernate.engine.spi.ActionQueue - Executing identity-insert immediately
23:35:47.062 [main] DEBUG org.hibernate.SQL -
insert
into
phone
(number, person_id)
values
(?, ?)
23:35:47.297 [main] DEBUG org.hibernate.engine.jdbc.spi.SqlExceptionHelper - could not execute statement [n/a]
java.sql.SQLIntegrityConstraintViolationException: Column 'person_id' cannot be null
Add the #GeneratedValue annotation to specify that the primary key for both entities will be populated outside of your code.
#Entity
#Table(name = "phone")
public class Phone {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#Column(name = "number")
private String number;
#JoinColumn("person_id")
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Person person;
//omit setter and getter
}
public class Person {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
private String username;
#OneToMany(mappedBy = "person")
private List<Phone> phones = new ArrayList<>();
//omit getter and setter
}
Additionally, you need to persist the Person object instead of the Phone object because there is no cascade configured from Phone to Person. If you can't do that, switch the CascadeType on Person to none and put the cascade on the Phone as shown above.
You should also add a #JoinColumn annotation on the Phone entity so hibernate is aware of the foreign key column.
You Missed something. You can try with this.
Person Entity
#Entity
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String username;
#OneToMany(mappedBy = "person")
private List<Phone> phones = new ArrayList<>();
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public List<Phone> getPhones() {
return phones;
}
public void setPhones(List<Phone> phones) {
this.phones = phones;
}
//omit getter and setter
}
Phone Entity
#Entity
#Table(name = "phone")
public class Phone {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "number")
private String number;
#ManyToOne(cascade = CascadeType.PERSIST)
private Person person;
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
//ommit setter and getter
}
Phone Dao
public interface PhoneDao {
public Phone save(Phone phone);
}
PhoneDaoImpl
#Repository
public class PhoneDaoImpl implements PhoneDao {
#PersistenceContext
private EntityManager entityManager;
#Override
public Phone save(Phone phone) {
return entityManager.merge(phone);
}
}
PersonDaoImpl
#Repository
public class PersonDaoImpl implements PersonDao{
#PersistenceContext
private EntityManager entityManager;
#Override
public Person save(Person person) {
return entityManager.merge(person);
}
}
Test Method
#Test
#Transactional
#Commit
public void say()
{
Phone phone = new Phone();
phone.setNumber("jghjkhk");
Person person = new Person();
person.setUsername("7576");
phone.setPerson(person);
Phone pers = phoneDao.save(phone);
Assert.assertNotNull(pers);
}
Try now. It will work.
I think that you need to set the value of the person->id and then also use an getter method to pass the id to your phone object instead of passing the person object
Normally people have hibernate set the id of an entity automatically with a surrogate key.
public class Person {
#Id #GeneratedValue // should pick an appropriate strategy here
private long id;
Since you don't have that you must either add it or set it yourself.
Person p = new Person();
p.setId(1); // hopefully unique
The same goes for phone.
As you are not having any generation type on your #Id and id is the primary key which can not be null so either you have to set value of id or have #GeneratedValue annotation on your id field and set strategy either as Auto or Identity.
You can also have your own sequence generation.
Also, you need to do same for the Phone class.

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

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