JPA, Map entity Person which contains class of type Name - jpa

I have an entity Person which consists of a name Attribute
#Entity
public class Person {
// ...
//#Transient
private Name name;
// ...
}
I dont want to store "name" in an extra table... I mark name as transient so it is not stored in the underlying database.
What I want is to map the attribute "name" to columns "first_name" and "last_name" in the database.
For example I can create a person like new Person(new Name("John","Doe"));
How can I achieve a mapping that the underlying table contains two additional columns first_name and last_name and the contents are the strings which I get from the name attribute?
The table, based on the person entity should look like
id|first_name|last_name
1 |John | Doe
2 |Jane | Doe

You can use embeddables:
#Embeddable
public class Name {
private String firstName;
private String lastName;
// getters and setters
}
And then use it like.
#Entity
public class Person {
// ...
private Name name;
// ...
}
Read more about embeddables in the Hibernate documentation: https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#embeddables

Related

Save entity with Spring data, persistence & db contraints

In my project I have e.g. an Employee which has several Mobile which has additional attributes, e.g.
Jon Doe, +911, private
Jon Doe, 123456, company
Jon Doe, 8978, company,
Mara Smith, 7888, private
Mara Smith, 458, company
and therefore I create
#Entity
public class Employee {
#Id
private int id;
#OneToMany(mappedBy="emp")
private List<Mobile> lstMobiles;
...
}
and for the Mobile I have
#Entity
#IdClass(MobileKey.class)
public class Mobile {
#Id
private String phoneNo;
#Id
#JoinColumn(name = "emp_id")
private Employee emp;
...
}
class MobileKey{
private String phoneNo;
private int emp;
....
}
The database has tables Employee, Mobile. The table Mobile first two columns are
emp_id (as int)
phoneNo (as String)
up till now nothing special except that the database has a foreign constraint, namely that the emp_id has to exist in the table Employee. Otherwise the phoneNo does not make much sense.
The major problem I'm facing right now is that I need to store Jon Doe or Mara Smith. If I use e.g.
public interface EmployeeRepository extends JpaRepository<Employee, Integer> {
}
with some Autowired variable as e.g. employeeRepo.save(newEmployee) than I get from the database a constraint violation. This is due to the fact that the Mobile is attempted to be inserted before the Employee is created in the table :-(
I guess that the design of Employee and the Mobile is somehow wrong - especially with the list and the relation. But could be as well be related with the Spring-Data configuration.

Model Look up table for a JPA Entity Field

I'm trying to find out the appropriate relationship to be used in order to model an JPA Entity Field which needs a Look-up table (Comboxbox equivalent on the UI) to select the value from. An example below:
#Entity
public class Employee {
#Id
private int employeeId;
private String name;
private Department department;
}
#Entity
public class Department {
#Id
private int id;
private String name;
}
The instances of Department could be as follows:
Id | Name
-----------------------
100 | Human Resources
101 | Sales
102 | Finances
For an employee, the department field should get a value from one of the above. What should be the JPA annotations for the corresponding fields in both the entities?
Thanks,
Sandeep Joseph
I think you are looking for a unidirectional ManyToOne relationship from Employee to Department, something like this:
#Entity
public class Employee {
#Id
private int employeeId;
private String name;
#ManyToOne
#JoinColumn(name = "department_id", nullable = false)
private Department department;
}
This means an employee must be associated to a single department and a department can be associated to many employees.
If you need to know the list of employees associated to a department then you can make the relationship bidirectional by adding this:
#Entity
public class Department {
#Id
private int id;
private String name;
#OneToMany(mappedBy = "department")
private Collection<Employee> employees;
}

Is the domain model/JPA entity model supposed to create a well-designed database table structure?

Let's assume the domain model of an application that is supposed to be built from scratch is described as follows:
A Person might live at an address. A Person can own multiple cars.
If I had to design the database first, I would probably come up with the following database design (normalization, cascading, etc. are not supposed to play a major role for my concrete question).
Person (id, name)
Address (id, street, zip, city, person_id)
Car (id, manufacturer, yearBuilt, color, person_id)
I have mainly followed standard design concepts (e.g. described in this link http://db.grussell.org/section006.html).
As you can see the address table has a foreign key to the person table as the person - address relationship can be considered optional.
The fact that a person can own multiple cars is implemented by putting a foreign key to a person in the car table. I think this is the standard way of modelling 1..m relationships.
If I had to design the domain model first, I would probably come up with the following design:
public class Person {
private String name;
private Address address;
private List<Car> cars;
// Getters and setters
}
public class Address {
private String street;
private String zip;
private String city;
// Getters and setters
}
public class Car {
private String color;
private Date yearBuilt;
// Getters and setters
}
In that domain model, the Person class has all necessary relationships. The Address and Car classes do not need to know anything about their owning Person.
I could now turn these classes into JPA entities by adding #Entity and providing an #Id attribute for every class.
#Entity
public class Person implements Serializable {
#Id
private Long id;
private String name;
#OneToOne
private Address address;
#OneToMany
private List<Car> cars;
public Person() { }
// Getters and setters
}
#Entity
class Address implements Serializable {
#Id
private Long id;
private String street;
private String zip;
private String city;
public Address() { }
// Getters and setters
}
#Entity
class Car implements Serializable {
#Id
private Long id;
private String color;
private Date yearBuilt;
public Car() { }
// Getters and setters
}
If my JPA provider creates the tables according to the provided annotations, the following database structure is created:
Person (id, name, address_id)
Address (id, street, zip, city)
Car (id, manufacturer, yearBuilt, color)
Person_Car (person_id, car_id)
As you can see, that does not correspond to the database structure I would create if I had to design the database first. I see a few flaws in the database model created by the JPA provider:
As the person - address relationship is optional, I would have put the foreign key to a Person into the Address table and not vice versa.
As the standard way of modelling a 1..m relationship is to put the foreign key of the owning class into the detail class, I would have never come up with a relation or association table. Why would I want to have that if the relation is not described by additional attributes?
To join a Person to a Car, the JPA provider needs to perform an additional join to the relation or association table. Does this measurably decrease the performance?
What I could do now is to provide the JPA entity classes with additional fields and/or annotations to strive for the database structure one might expect.
Is it desirable to strive for a domain model/JPA entity design that is able to create an expected database structure (as if database-first-approach was used)? If so, is it acceptable to have a domain model that is different from a domain model one would create intuitively? What are the advantages in designing a domain model/JPA entity model that will create some sort of "best practice" database structure?
Update the mapping from Person to Car as below:
#OneToMany
#JoinColumn(name = "person_id")
private List<Car> cars;
the DDL generator of your JPA provider should then create the desired table structure.

Persisting properties of nested objects

I have a table "user" with fields name, city, state, country. And then, I have a class "User" as below:
class User{
String name;
Address address;
}
The Address class has following:
class Address{
String city;
String state;
String country;
}
Now, how can I save the "name" field of User class and properties of Address class within same entry in "user" table?
You should mark an Address class as #Embeddable
Specifies a class whose instances are stored as an intrinsic part of
an owning entity and share the identity of the entity. Each of the
persistent properties or fields of the embedded object is mapped to
the database table for the entity.
an example
#Embeddable
class Address{
String city;
String state;
String country;
}
and than
class User{
String name;
#Embedded
Address address;
}
the #Embedded annotation is not required, but makes the embeddable relationship more explicit

JPA annotation to add and view values from a reference table

Say I have this class:
#Entity
#Table(name="PICTURE")
public class Picture{
private String category1, category2;
}
but the database structure looks like this:
TABLE PICTURE {
int category1;
int category2;
...
}
TABLE PICTURE_REF {
int category;
String categoryName;
...
}
How would I use JPA annotations on Picture so that any time I request an instance of it, category1 and category2 contains the categoryName from the PICTURE_REF table instead of the actual integer id stored in the PICTURE table?
I'm also wondering how saves would work because the user would select a category from a dropdown and the corresponding category integer ID would be what's stored in the PICTURE table.
From your description , PICTURE.category1 and PICTURE.category2 have the many-to-one relationship to the PICTURE_REF
The following shows the bi-directional mapping between them using annotation:
For table PICTURE:
#Entity
#Table(name="PICTURE")
public Class Picture{
#Id
private Integer id;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "category1")
private PictureRef category1,
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "category2")
private PictureRef category2;
//getter and setters
}
For table PICTURE_REF:
#Entity
#Table(name="PICTURE_REF")
public Class PictureRef{
#Id
private Integer id;
#OneToMany(mappedBy = "category1")
List <Picture> listOfCat1Picture= new ArrayList<Picture>();
#OneToMany(mappedBy = "category2")
List <Picture> listOfCat2Picture= new ArrayList<Picture>();
//getter and setters
}
Important Points:
#Entity marks the java class as an hibernate entity. It is mapped to the name of the table specified in the #Table
Use #ManyToOne to define the many-to-one relationship
In the relational database , many-to-one relationship is expressed by using the following foreign key constraint:
"Many side table" has a FK column which only accepts the PK of the "one side table".
In your case , these FK columns are PICTURE.category1 and PICTURE.category2. The name of these FK columns can be explicitly defined by the name attribute of #JoinColumn.
FetchType.EAGER makes that PictureRef will be eagerly fetched whenever Picture is loaded or get
Depending on your requirement , you can do the unidirectional mapping by omitting #OneToMany in the PictureRef.It will also work .But given PictureRef , you cannot access its Picture
Given a Picture instance , you can get its categoryName and categoryId by
picture.getCategory1().getCategoryName()
picture.getCategory1().getId()
picture.getCategory2().getCategoryName()
picture.getCategory2().getId()
If you can't modify the schema
You can modify your mapping so Category is an entity instead of just a String. Then you would have a OneToOne or (more likely) a ManyToOne from Picture to Category for category1 and category2.
If you CAN modify the schema
You can use an ElementCollection on Picture to store a List instead of having category1 and category2. This would give you a schema something like
TABLE PICTURE {
long key;
}
TABLE PICTURE_CATEGORY {
long picture_key;
String category_name;
}
OR you can again map Category to an entity and use a ManyToMany from Picture to Category which would give you a schema like
TABLE PICTURE {
long key;
...
}
TABLE PICTURE_CATEGORY {
long picture_key;
long category_key;
}
TABLE CATEGORY {
long key;
String name;
}
As for saving, you will can use a converter in whatever your view technology is that will converter from key to Category, or you can load the Category from the key in your controller and set it in the Picture before you save. I doubt you'll want saving a Picture to cascade into a Category.