I am studying for the Spring Core certification and I have some doubts about how works the Embeddables JPA class.
So I have this example:
1) A Customer entity class that map the T_CUSTOMER DB table
#Entity
#Table(name= “T_CUSTOMER”)
public class Customer {
#Id
#Column (name=“cust_id”)
private Long id;
#Embedded
#AttributeOverride
(name="postcode", column=#Column(name="ZIP"))
private Address office;
…
…
…
}
2) An Address entity class that simply represent an address (and that not map any DB table):
#Embeddable
public class Address {
private String street;
private String suburb;
private String city;
private String postcode;
private String country;
}
As you can see in the Customer entity class there is this field:
#Embedded
#AttributeOverride
(name="postcode", column=#Column(name="ZIP"))
private Address office;
What exactly are the rules and the meaning of the #Embedded and #AttributeOverride annotations?
I think that this works in the following way:
1) Some column of the T_CUSTOMER DB table are mapped not directly into the Customer entity class but are mapped and stored into the field of the Address class that is a field of the the Customer class.
2) The table column named ZIP is mapped with the postcode property of the Address class.
Is it right or am I missing something?
Tnx
Related
I have a Student table with Columns name, age, gender and address.
Is it possible to create a Java POJO class with #Entity annotation and
have only name and address in it?
#Entity
#Table(name="Student")
public class Student {
#Column(name = "name")
String name;
#Column(name="address")
String address;
}
I am new to Spring boot and searched a bit around this but couldn't get any specific answer.
When I use an #Embedded class in Java / JPA, how is this mirrored in the database?
For instance, if I have an #Entity User with an #Embedded #Entity Address:
#Entity
#Table(name="User")
public class User {
#ID
private Long u_id;
#Column(name="name")
private String name;
#Embedded
private Address address;
}
#Entity
#Table(name="Address")
public class Address {
#Column(name="street")
private String street;
#Column(name="zip")
private String zipcode;
....
}
Will this result in two tables referenced using a foreign key or will there be just ONE table containing aLL columns of both entities (what would be not well normalized)?
First of all, you can't use #Embedded and #Entity together. Your class Address must be marked as #Embeddable.
Then.
If you are using #Embedded and #Embeddable - it will one table with columns of both classes.
If you are using #Entity and #OneToMany (or #OneToOne, #ManyToOne, #ManyToMany) it will be different tables;
Hibernate Mapping
How to implement such a code?
Each company has two properties, they are company name and estimated annual earnings.
There are two types of companies: 1- Main company, 2 - Subsidiary company.
The company can belong only to one company but can have a few child companies.
public class Company {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String companyName;
private double estimatedAnnualEarnings;
private Company company; // here need to do a #OneToOne
private List<Company> subsidiaryCompany; // here need to do a #OneToMany
}
In your Implementation you should use :
The #Entity annotation in your class level, so the entity can be persisted to database.
The #Column annotation with the companyName and estimatedAnnualEarnings properties, so they can be persisted as columns in the database.
#ManyToOne annotation with the company field, so it can be mapped with a self-reference relationship.
The same goes with the subsidiaryCompany List which needs to be mapped with #OneToMany annotation to have a relationship too.
This is how should be your code:
#Entity
public class Company {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column
private String companyName;
#Column
private double estimatedAnnualEarnings;
#ManyToOne(cascade={CascadeType.ALL})
#JoinColumn(name="mainCompanyId")
private Company mainCompany;
#OneToMany(mappedBy="mainCompany")
private List<Company> subsidiaryCompanies;
//getters and setters goes here
}
Note
I changed the name of company field to mainCompany and
subsidiaryCompaniy to subsidiaryCompanies for better readability
and to make it fit the logic better.
If you want to give your entity a different name in the database you
should use #Table(name="differentName") in the class level with
#Entity annotation, the smae thing with the columns you can add
name property to the #Column annotation i.e
#Column(name="company_name") if you want different names.
I am a JPA newbie. I have what I believe is a very simple example, but I am having trouble implementing it. Basically, I have an entity that I want to "reuse" in other entities.
I have a User having two fields - Home and Office. Each of these in turn refers to an Address, like so:
#Entity
public class User extends Model {
#Column
private String name;
#OneToOne
private Home home;
#OneToOne
private Office office;
}
#Entity
public class Home extends Model {
#OneToOne
private Address address;
#OneToOne(mappedBy="home")
private User user;
// ...
}
#Entity
public class Office extends Model {
#OneToOne
private Address address;
#OneToOne(mappedBy = "office")
private User user;
// ...
}
#Entity
public class Address extends Model {
#Column
private String line1;
#Column
private String line2;
#Column
private String city;
/*
* Is this possible? Being owned by two entities?
*/
#OneToOne(mappedBy="address")
private Home home;
#OneToOne(mappedBy="address")
private Office office;
// ...
}
How do I achieve this?
EDIT
I was originally running into this exception:
org.hibernate.AnnotationException: #OneToOne or #ManyToOne on example.Home.address references an unknown entity: example.Address
It turns out that one of the classes had imported the #Entity annotation from org.hibernate instead of from javax.persistence. After fixing this, the original exception went away (this helped me pin point the issue)
However, I now have a new exception:
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: example.User.home -> example.Home
I don't quite understand this exactly. Should I call save the Home object before I do so on the User instance?
I fixed the problem by adding cascade=CascadeType.ALL attribute to all the #OnetoOne annotations in all the entities.
Without this annotation, I would have to save each owned entity before saving the owning one. For example, I'd have to save a Home before saving the User that the home belongs to.
Adding the cascade attribute to the annotation takes care of this for you. You only need to save the User and the Home and Addresses are automatically saved for you.
This post helped me solve the problem.
Can you make only 1 class User:
#Entity public class User extends Model
{
#Column
private String name;
#Embedded
#AttributeOverrides({
#AttributeOverride(name = "line1", column = #Column(name="column11")),
#AttributeOverride(name = "line2", column = #Column(name="column21")),
#AttributeOverride(name = "city", column = #Column(name="column31"))
})
private Address homeAddress;
#Embedded
#AttributeOverrides({
#AttributeOverride(name = "line1", column = #Column(name="column12")),
#AttributeOverride(name = "line2", column = #Column(name="column22")),
#AttributeOverride(name = "city", column = #Column(name="column32"))
})
private Address officeAddress;
// .. setters, getters
}
#Embeddable
public class Address extends Model
{
private String line1;
private String line2;
private String city;
// .. getters, setters
}
is there a simple way to persist some of the fields in another class and table using hibernate.
For example, I have a Person class with name, surname, email, address1, address2, city, country fields. I want my classes to be:
public class Person
{
private String name;
private String surname;
private String email;
private Address address;
// ..
}
public class Address
{
private Person person; // to whom this belongs
private String address1;
private String address2;
private String city;
private String country;
// ..
}
and I want to store Address in another table. What is the best way to achieve this?
Edit: I am using annotations. It does not have to be the way I described, I am looking for best practices.
Edit 2: What will be the Id of Address?
PS. If there is a way to make Address immutable (to use as a value object) that is even better, or maybe not because I thought everything from wrong perspective :)
map Address as an entity and add a primary key (an auto-generated id)
map the relation between Person and Address as one-to-one (#OneToOne on each field)
With Hibernate 3.5 it is possible to define foreign generators (aka. JPA mapping), details are here.
It is pretty straight forward Person should implement Serializable then #Id annotation is added to person.
#Entity
#AccessType(value = "field")
#Table(name = "addresses")
public class Address
{
#Id
#OneToOne
#JoinColumn(name = "person_id")
private Person person;
// ...
}
There is an alternative but I really like the first one:
#Entity
#AccessType(value = "field")
#Table(name = "addresses")
public class Address
{
#Id
private int personId;
#MapsId
#OneToOne
#JoinColumn(name = "person_id")
private Person person;
// ...
}