Joining two tables Hibernate - java

I am working with Spring MVC + Hibernate ( Spring data jpa ).
Here I am not getting how to create a table in Hibernate for the following scenario.
I have two tables :
1) User Details
2) Branch
Now, For every user, there is a field for branch, and that value should be from Branch table.
I have knowledge of OneToOne in hibernate. But it inserts a new entry for users branch field in Branch table. What I want is that, when I save user details in User Table, branch details should be just a reference from Branch table for matching row.
Thank you in advance

Suppose your branches can be identified by their names:
UserDetails user = new UserDetails();
...
user.setBranch(branchRepository.findOneByName());
...
userDetailsRepository.save(user);
Having:
#Entity
public class UserDetails {
#Id
#GeneratedValue
Long id;
#ManyToOne
Branch branch;
...
}
#Entity
public class Branch {
#Id
#GeneratedValue
Long id;
...
}
public interface BranchRepository extends Repository<Branch, Long> {
...
}
public interface UserDetailsRepository extends Repository<UserDetails, Long> {
...
}

You can use the User-Branch relationship by controlling the association through its Foreign Key.
And inside the User class, you will specify the OneToOne mapping as follows:
#OneToOne
#JoinColumn(name="User_Branch_ID")
private Branch branch;
And this "User_Branch_ID" refers to the foreign key which you have created while creating the User database table as follows:
create table BRANCH (
branch_id BIGINT NOT NULL AUTO_INCREMENT,
   name VARCHAR(30) NOT NULL,
   city  VARCHAR(30) NOT NULL,
   country  VARCHAR(30) NOT NULL,
   PRIMARY KEY (address_id)
);
 
create table USER (
   user_id BIGINT NOT NULL AUTO_INCREMENT,
   user_branch_id BIGINT NOT NULL,
   first_name VARCHAR(30) NOT NULL,
   last_name  VARCHAR(30) NOT NULL,
   PRIMARY KEY (user_id),
   CONSTRAINT user_branch FOREIGN KEY (user_branch_id) REFERENCES BRANCH ( branch_id)
);

step 1: create a view
create view v_BRANCH_USER as
select
a.branch_id, a.name , a.city, a.country
b.user_id,b.first_name, b.last_name
from BRANCH a, USER b
where a.branch_id = b.user_branch_id
step 2: create a pojo and mapping to hibernate as a table
#Entity
#Table(name = "v_BRANCH_USER")
public class VBranchUser
String userId;
....
}
step 3: You can query it as a table (Criteria, HQL ..)

Related

Join column from another table with Foreign Key using JPA

I'm new to JPA and trying to understand if there's a way to make an Entity where one column is coming from another table that is linked by a foreign key. For example, consider the following tables:
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`email` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `jobs` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11),
PRIMARY KEY (`id`),
CONSTRAINT `fk_jobs_users` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
);
Now I want to make an Entity for the "jobs" table that will include the user.email. I know I can do something like
#Entity
#Table(name = "jobs")
public class JobEntity {
#Id
#Column(name = "id")
private Long id;
#Column(name = "user_id")
private Long userId;
#Formula("(select user.email FROM user WHERE user.id = user_id)")
private String userEmail;
But I feel there's a way I can better leverage the foreign key relationship, but I'm not sure how. I was looking into #JoinColumn but was not seeing the result I wanted since the foreign key is a different column in my Entity. Is there a better way rather than using #Forula to do this?
I don't really understand this. I'm sure #JoinColumn can accomplish the behavior you're looking for.
I was looking into #JoinColumn but was not seeing the result I wanted since the foreign key is a different column in my Entity
Example:
#Entity
#Table(name = "jobs")
public class KronosFileEntity {
#Id
#Column(name = "id")
private Long id;
#ManyToOne
#JoinColumn(name = "user_id", referencedColumn = "id")
private User user;
}
Then you can access the email like job.getUser().getEmail()
Or add a convenience method if that helps
public String getUserEmail() {
return user.getEmail();
}
Then
job.getUserEmail()

Spring data jdbc one-to-many wrong join

I'm using spring-boot 2.3.3 and spring-data-jdbc 2.0.3 to model a relationship between to elements guitar and classType. A guitar has a classType.
My schema in H2 (also in MySQL) is this:
CREATE TABLE class_type (
id bigint NOT NULL AUTO_INCREMENT,
description varchar(50) NOT NULL
PRIMARY KEY (id)
);
CREATE TABLE guitars (
id bigint NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
description varchar(1000) NOT NULL,
classType bigint NOT NULL,
PRIMARY KEY (id),
UNIQUE (name),
FOREIGN KEY (classType) references class_type(id)
);
And I have these classes:
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Table(value = "guitars")
public class Guitar {
#Id
long id;
String name;
String description;
#MappedCollection(idColumn = "id")
#Column(value = "classType")
ClassType classType;
}
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Table(value = "class_type")
public class ClassType {
#Id
Long id;
String description;
}
My repository is like this:
#Repository
public interface GuitarRepository extends CrudRepository<Guitar, Long>, PagingAndSortingRepository<Guitar, Long> {}
When I invoke this test:
#SpringBootTest
public class GuitarOneManyTest {
#Autowired
GuitarRepository guitarRepository;
#Test
void findAllByName() {
System.out.println(guitarRepository.findAll());
}
}
This sentence appears with an incorrect LEFT OUTER JOIN
SELECT `guitars`.`id` AS `id`, `guitars`.`name` AS `name`, `guitars`.`description` AS `description`, `classType`.`id` AS `classType_id`, `classType`.`description` AS `classType_description` FROM `guitars` LEFT OUTER JOIN `class_type` AS `classType` ON `classType`.`id` = `guitars`.`id`
But I want the select to be like this:
SELECT (...) FROM `guitars` LEFT OUTER JOIN `class_type` AS `classType` ON `classType`.`id` = `guitars`.`classType`
Did I miss something?
This is not a one-to-many relationship. One Guitar would reference multiple ClassType instances.
Instead it seems to be intended as a many-to-one relationship: Many Guitar instances might reference the same ClassType. This makes ClassType a different aggregate from Guitar and therefore it must not be referenced by a direct java reference, but only by it's id.
See Spring Data JDBC, References, and Aggregates for a more detailed explanation how to model such a relationship with Spring Data JDBC.

Use JPA entity id without #GeneratedValue annotation

I'm working with spring-boot-starter-data-jpa. Should I use annotation #GeneratedValue on my entity id if my code working without it and generate PRIMARY KEY automatically in mysqldb?
When I run the test in the sqltable appears new row with an ID with the following AUTO_INCREMENT value, while passed every time id 0.
Entity
#Data
#Entity
#RequiredArgsConstructor
#NoArgsConstructor(access = AccessLevel.PRIVATE, force = true)
public class Person {
#Id
// #GeneratedValue(strategy = GenerationType.IDENTITY)// use or not - the same effect
private int id;
#NonNull
private String name;
#NonNull
private String surname;
}
Repository
public interface PersonRepository extends CrudRepository<Person, Integer> {
Person findByNameAndSurname(String name, String surname);
}
Testing
#RunWith(SpringRunner.class)
#SpringBootTest
public class SpringRestInventoryPersistenceTests {
#Autowired
private PersonRepository personRepository;
#Test
public void personPersist() {
Person person = new Person("John", "Smith");
assertTrue(person.getId() == 0);
personRepository.save(person);
assertTrue(person.getId() == 0);
Person person2 = personRepository.findByNameAndSurname("John", "Smith");
assertEquals(person.getName(), person2.getName());
}//test passed
mySql table
CREATE TABLE `person` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
`surname` varchar(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8
I was also facing the same issue , I have added sequence generator in DB say 'idGenerator' ,and then add
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator="idGenerator")
#SequenceGenerator(name='dbname' , sequenceName="idGenerator") ,
This will take the values from sequence generator created in DB
I`ve understood the reason for this behavior. Without the #GeneratedValue annotation, ID is not generated automatically and ID with value 0 is always passed to the mysql database. In this case mysql generate ID value from AUTO_INCREMENT. This is default behavior.
To disable this behavior you can set next parameter:
SET SQL_MODE='NO_AUTO_VALUE_ON_ZERO'
Then after second call test method personPersist() we get error. In this case we can`t generate ID in mysql DB without #GeneratedValue annotation.

Why Can't I Delete this Record (Table Constraints) - I am using Spring and Hibernate

I am having problem deleting a record from my database table. I get Constraintviolation exception. I'm dealing with Categories and Sub-categories. I have a Category class that has parent which also refer to the same Category class. Categories with no parent will have the parent field be null. In the table below all empty parent columns means those categories are parent categories.
I am using Spring boot and Spring data so the repository and the delete() methods are created automatically. I just call the delete() method in my controller class.
I have the following class
#Entity
#Table(name="category")
public class Category {
#Id
#Column(name="id")
private String id = IdGenerator.createId();
#Column(name="name", nullable=false, unique=true)
#Size(min=2, max=60, message="LATER")
private String name;
#ManyToOne//(cascade=CascadeType.ALL)
#JoinColumn(name="parent", nullable=true)
private Category parent;
#OneToMany(mappedBy="parent")
private Set<Category> children = new HashSet<Category>();
//GETTERS AND SETTERS HERE
}
and the following table ::
CREATE TABLE category(
id varchar(255) NOT NULL,
name varchar(255) NOT NULL,
parent varchar(255) DEFAULT NULL,
PRIMARY KEY (id),
FOREIGN KEY (parent) REFERENCES category (id)
);
with the following records in the table::
id name parent
1 Furnitre
2 barbecue 1
3 Home and Garden
4 Fashion 3
5 Restaurants 3
Now when i try to delete record 5 (Category record in row 5) i get
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`grabone`.`category`, CONSTRAINT `category_ibfk_1` FOREIGN KEY (`parent`) REFERENCES `category` (`id`))
I think this shouldn't be the case because record 5 has no children and i have to be able to delete it.
What am i doing wrong?
UPDATE
This is my controller code to delete Category. There is something rare going on here ::
#DeleteMapping(value = DELETE)
public ResponseEntity<?> delete(#PathVariable("categoryId") String categoryId){
Category cat = categoryService.findById(categoryId);
categoryService.delete(cat);
return new ResponseEntity<>("", HttpStatus.OK);
}
The above code works now. It deletes Category from the table but the following don't. It generates the above Exception. WHY?
#DeleteMapping(value = DELETE)
public ResponseEntity<?> delete(#PathVariable("categoryId") String categoryId){
categoryService.delete(categoryId);
return new ResponseEntity<>("", HttpStatus.OK);
}
In Spring Data repository, there are two delete() methods::
void delete(String id);
void delete(Category category);
One that takes id and the other that takes the Object of the class. Why is it that the one that takes the id doesn't work?

Creating row in child table using jpa when we have a row in parent table

I have 2 tables:
CREATE TABLE `addr1` (
`id` int(11) DEFAULT NULL,
`addr2` varchar(20) DEFAULT NULL
) ENGINE=InnoDB;
CREATE TABLE `address` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`address` varchar(250) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
primary key of addr1 is set from address table. I created my entities using joined inheritance as
#Entity
#Table(name="addr1")
public class Addr1 extends Address {
#Column(name="addr2")
private String addr2;
// getters and setters follows
}
#Entity
#Table(name = "address")
#Inheritance(strategy=InheritanceType.JOINED)
public class Address implements Serializable {
#Id
#GeneratedValue
#Column(name = "id")
private int id;
#Column(name = "address", nullable = false, length = 250, insertable = true)
private String address;
// getters and setters follows
}
Now I have a row in address table with id 2. I want to inset a row in addr1 table with same id (2). I had tried
Address addr = em.getReference(Address.class, new Integer(4));
Addr1 addr1 = new Addr1(addr);
addr1.setAddr2("dsdsd");
em.persist(addr1);
but I am getting an error
javax.persistence.PersistenceException:
org.hibernate.PersistentObjectException: detached entity passed to
persist: Addr1
Please help me.
Regards,
Praveen
It's impossible. Inheritance implies a is-a relationship. Your entity instances can thus be either a bare Address, or an Addr1. And a Java object can't change its type. You can't take an object of type Object, and ask the JVM to change its type and make it an object of type String instead. It's the same here.
If you need to do that, then you should use composition, not inheritance: an Address can have an Addr1. And you should thus have a OneToOne association beteween Address and Addr1, instead of an inheritance relationship.

Categories

Resources