I have three tables:
1. Catalog (PK: id, name, FK: genre_id, FK: type_id)
2. Type (PK: id, name)
3. Genre (PK: id, name)
How to use Hibernate to connect Genre and Type to Catalog by using annotation?
#Entity
#Table(name = "catalog")
public class Catalog implements Serializable {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "product_name")
private String productName;
private Genre genre; // to add
private Type type; // to add
...
}
If you want to connect Genre and Type to Catalog (is this what you mean?), you should include in both Genre and Type entities a Collection<Catalog>-typed field and annotate it with #OneToMany.
If not, the straightest way is to add the #ManyToOne annotation to Genre and Type fields in Catalog.
Related
I'm new at Spring Boot's JPA concept so need your help in deciding how to import just the ID of another entity, say User into HealthData entity. Following is my User entity:
#Entity
#Table(name = "user",uniqueConstraints = {#UniqueConstraint(columnNames = "email")})
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(nullable = false)
private String name;
#Email
#Column(nullable = false)
private String email;
private String imageUrl;
#Column(nullable = false)
private Boolean emailVerified=false;
#JsonIgnore
private String password;
#NonNull
#Enumerated(EnumType.STRING)
private AuthProvider authProvider;
private String providerId;
}
And I wish to define HealthData entity in the following manner :
#Entity
#Table(name = "HealthData",uniqueConstraints = {#UniqueConstraint(columnNames = "id")})
public class HealthData {
#Id
private Long id; //how to import id of User here?
#Column
private Double height;
#Column
private Double weight;
#Column
private int age;
...other columns
}
Now, I wish to use Id of User to this entity(kind of making parent-child relationship) . I don't want to add User class object in HealthData. I thought of using #OneToOne in HealthData but then it would add User in it. How can i just include Id from parent table in child table?
In this case, your HealthData has a reference to User, and I'm not sure why you wouldn't have mapped this as a foreign key. If you are able to do so, I'd suggest the following:
#Entity
#Table(name = "HealthData")
public class HealthData {
#Id
#OneToOne
#JoinColumn(name = "id")
private User user;
#Column
private Double height;
#Column
private Double weight;
#Column
private int age;
...other columns
}
JPA then handled setting the "ID" to the value within your user instance for you, and can persist both in the same transaction automatically. Allowing references to be marked as IDs is known as a derived ID and supported I believe since JPA 2.0.
As for efficiency, you can still lazy fetch or even not fetch the user instance. It is simple to just map the ID column as a basic using a slightly different approach:
#Entity
#Table(name = "HealthData")
public class HealthData {
#Id
private Long id;
#MapsId
#OneToOne(optional = false, fetch = FetchType.LAZY)
#JoinColumn(name = "id")
private User user;
#Column
private Double height;
#Column
private Double weight;
#Column
private int age;
...other columns
}
JPA will set both the User id as well as the healthData.id values based on what it generates for the user Id sequence when you set the healthData.user reference.
You can use getters and setters to set the value of user id in the healthdata table.
Could you please advise how to write query in Spring Data JPA repository? Here is the situation:
I have 2 Entities: Customer and Product with relationship 'OneToMany' - means one Customer may have many products. In code it looks like Customer entity has Set products and Product has reference to Customer customer, very simple. If I retrieve Customer from DB JSON would look like this: {"id":10, "name":'John Smith',"personalCode":12345678,"products":[ {"id":15,"type":"productType1"}, {"id":20,"type":"productType2"}] }
The question is how can I write query to DB to find all customers whose products match passed products collection? For example I want to find all customers who owns products with type1 and type2. THANKS!
#Entity
#Table(name = "customer")
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private int age;
private String personalCode;
#Enumerated(EnumType.STRING)
private Country country;
private String internetBankUserId;
#Enumerated(EnumType.STRING)
private CustomerType type;
#JsonManagedReference
#OneToMany(mappedBy = "customer", cascade = CascadeType.ALL)
#SortNatural
private SortedSet<Product> products = new TreeSet<>();
#Entity
#Table(name = "product")
public class Product implements Comparable<Product>{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Enumerated(EnumType.STRING)
private ProductType type;
#JsonBackReference
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "customer_id")
private Customer customer;
This solution worked for me:
#Query("SELECT c FROM Customer c join c.products p where p.type in :products
and SIZE(c.products) >= :count")
Set<Customer> findAllByProductType (#Param("products")Set<ProductType> products,
#Param("count") Integer count );
I have a
company table
department table
employee table.
I am using hibernate to persist data in the database.
1. One to Many Relationship between Company and Department .
A company can have multiple departments and a department can have multiple employees.
I have done corresponding one to many mapping of entities as mentioned in below code. Request to update these entities comes from UI in the JSON format.
I have provided company Id, department Id, and employee Id in the request.
Now Suppose If for a particular company , there is one department in the database with dept_id 3 . . In the Json request, I get a request to update that particular company with one more department. So after updation, previous entry should remain as it is, i.e department with ID 3 ,should remain untouched and new entry should be added with some department Id, say 4,.
Now that company would have two departments one with Id 3 and other with id 4.
How could this be achieved??..Also department entries , which are not there in the request, should be deleted from the database... Same goes for the relation between employee and department,.request may ask to add new employee for a particular department,keeping the existing one.
Please help me with this, what configuration/approach has to be done in my code, to achieve this.
Here is the code for these three tables:
#Entity
#Table(name = "COMPANY")
#Getter
#Setter
public class Company implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "company_id")
private long companyId;
#Column(name = "company_region")
private String companayRegion;
#Column(name = "company_code")
private String companyCode;
#OneToMany(mappedBy = "company", cascade = CascadeType.ALL)
private List<department> departments;
public Company() {
}
}
#Entity
#Table(name = "Department")
#Getter
#Setter
public class Department implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "dept_id")
private long departmentID;
#Column(name = "dep_code")
private String departmentCode;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "company_id")
private Company company;
#OneToMany(mappedBy = "department", cascade = CascadeType.ALL)
private List<Employee> employees;
}
#Entity
#Table(name = "Employee")
#Getter
#Setter
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "employee_id")
private long employeeId;
#Column(name = "emp_code")
private String empCode;
#Column(name = "emp_name")
private String empname;
#Column(name = "employee_city")
private String employeeCity;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "dept_id")
private Department department;
}
the mappings seem correct, what you need is to use merge to obtain an Hibernate-managed entity and copy the fields from the detached instance (coming from the REST api):
Company c = (Company) session.merge(companyFromDto);
Merge should take care to create a new Company, or update an existing one (depending if it is already in the DB) as well as cascade the associations.
Make sure your JSON contains companyId / departmentID / employeeId
Load the company by companyId
INSERT all department entries where departmentID == 0, and fetch the generated ID (Hibernate will update the POJO, or return a new one with the ID set)
UPDATE all department entries where departmentID > 0, and remember the used departmentID
Iterate over company.getDepartments() and iterator.remove() entries with departmentID not contained in the collection built from (3) and (4)
By persisting the company Hibernate will detect which departments were removed, and delete those
Do basically the same for the department -> employee relationship
I have 2 tables, the first one is quite variable, the second one contains only constants:
USER.ID USER.NAME USER.USER_TYPE (FK on USER_TYPE.ID)
INT VARCHAR(64) INT(1)
----------------------------------
1 Alex 3
2 Jane 1
3 Carl 3
USER_TYPE.ID USER_TYPE.VALUE
INT(1) VARCHAR(64)
------------------------------
1 PENDING
2 REGISTERED
3 BANNED
4 ACTIVE
The foreign key USER.USER_TYPE is required and refering to a primary key USER_TYPE.ID in table USER_TYPE (one-to-one relation). Here is my mapping in Hibernate.
User.java
#Entity
#Table(name = "USER")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private int id;
#Column(name = "NAME")
private String name;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "USER_TYPE")
private UserType userType;
}
UserType.java
#Entity
#Table(name = "USER_TYPE")
public class UserType {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private int id;
#Column(name = "VALUE")
private String value;
}
My goal is to keep the enumerated values in the database. How to map UserType's value instead of id to User and validate it? I want to pass the constant VALUE to the String instead of its ID.
private String userType;
The expected result of the first user would be:
User[id=1, name=Alex, userType=Banned]
User[id=2, name=Jane, userType=Pending]
User[id=3, name=Carl, userType=Banned]
My attempt was to use this annotation on definition of table twice with both colums switched
#SecondaryTable(name="USER_TYPE",
pkJoinColumns={#PrimaryKeyJoinColumn(name="ID", referencedColumnName="USER_TYPE")}
)
and get the VALUE with
#Column(table="USER_TYPE", name="VALUE")
private String UserType;
however it leads to the error
Unable to find column with logical name: USER_TYPE in org.hibernate.mapping.Table(USER) and its related supertables and secondary tables
First you need to change the relation from #OneToOne to #ManyToOne as UserType can be used by one or many User and User can have one and one UserType.
Secondly use referencedColumnName which references :
The name of the column referenced by this foreign key column.
So User entity will be:
#Entity
#Table(name = "USER")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private int id;
#Column(name = "NAME")
private String name;
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "USER_TYPE", referencedColumnName = "VALUE")
private UserType userType;
}
In UserType you should apply a unique constraint using #NaturalId to value field + do not provide its setter, to prevent duplicate values as It may lead to inconsistency:
#Entity
#Table(name = "USER_TYPE")
public class UserType {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private int id;
#NaturalId
#Column(name = "VALUE")
private String value;
}
Hope it solves the issue!
Enumerations could be simpler:
enum UserType {
PENDING,
REGISTERED,
BANNED,
ACTIVE
}
#Entity
#Table(name = "USER")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private int id;
#Column(name = "NAME")
private String name;
#javax.persistence.Enumerated
private UserType userType;
}
If you really need separated table and #OneToOne relation, you can use #Formula from Hibernate:
#Formula("(select ut.value from user_type ut where ut.ID = USER_TYPE)")
private String userType;
For this really special requirement you could use SecondaryTable annotation.
That is, you don't need UserType entity, but declare attribute userType as String in User entity with column mapping to the secondary table "USER_TYPE".
First of all, I suggest you use ManyToOne relation. and Not CascadeType.ALL if you are not planning update or delete on USER_TYPE table.
If you do not need adding new UserTypes frequently use enum for it. It will just work as you want.
Second solution: As long as fetch = FetchType.EAGER you can add A transient field and return value of UserType in getter.
I am new to Hibernate and I am trying to figure out how to query a many to many relationship mapped as an entity due to the need of an extra column.
In particular, following the example I found at codejava.net (http://www.codejava.net/frameworks/hibernate/hibernate-many-to-many-association-with-extra-columns-in-join-table-example) I mapped the relation like this:
Student.java
#Entity
public class Student implements Serializable {
#Id
#Column
private String email;
#Column(nullable = false)
private String password;
#Column(nullable = false)
private String name;
#Column(nullable = false)
private String surname;
// Constructor, getters, setters, hashcode, equals
}
Course.java
#Entity
#Table(
uniqueConstraints = #UniqueConstraint(
columnNames {"name","year"})
)
public class Course implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column
private long id;
#Column
private String name;
#Column
private String year;
#OneToMany(mappedBy = "course")
private Set<Student_Course> students = new LinkedHashSet<>();
// Constructor, getters, setters, hashcode, equals
}
Student_Course.java
#Entity
public class Student_Course implements Serializable {
#Id
#GeneratedValue (strategy = GenerationType.IDENTITY)
#Column
private long id;
#ManyToOne
#JoinColumn(name = "student_email")
private Student student;
#ManyToOne
#JoinColumn(name = "course_id")
private Course course;
#Column(nullable = false,
columnDefinition = "int default 0")
private int score;
// Constructor, getters, setters, hashcode, equals
}
Now what I want to achieve is to find out, with an hql query, the names and surnames of students enrolled in a given course (I know the name and the year of the course).
I know this is probably easy, but I can't produce a working query in HQL.
Thank you in advance.
I believe that this query can do what you want:
SELECT sc.student.name, sc.student.surname
FROM Course c JOIN c.students sc
WHERE c.name = :name AND c.year = :year
Select name, surname from Student where email in
(Select student.email from Student_Course
where Student_course.course.name=:courseName and Student_course.course.year= :year)
and then set both courseName and year
Update
Select student.name,student.surname from Student_Course
where Student_course.course.name=:courseName and Student_course.course.year= :year