Untitled
Untitled
Basic Concepts:
SQL
HQL
JPQL
USER_MASTER UserMaster.java
UserMasterImpl.java
ROLE_MASTER RoleMaster.java
RoleMasterImpl.java
CSTMR_ACCNT_DTLS CstmrAccntDtls.java
CstmrAccntDtlsImpl.java
4. Table name should have max 30 characters. If it is crossing the limit, you have
to remove the vowels but not the initials.
CREATED_BY
CREATED_DATE
UPDATED_BY
UPDATED_DATE
7. For every primary key create dedicated sequence to generate primary key column
value.
Environment Setup:
1. Install Database
2. Add some dependencies:
a. spring-boot-starter
b. spring-boot-starter-data-jpa
c. Driver (situational)
d. Lombok (Optional)
Dynamic class creation:
Repository
CrudRepository
ListCrudRepository
PagingAndSortingRepository
ListPagingAndSortingRepository
*** Note: Your UserRepository must extend any of these 5 Repository classes. Then
only your UserRepository will be implemented dynamically.
CrudRepository
Usage:
3. use JPQL
CrudRepository methods:
C - Create / Insert
R - Read
U - Update
D - Delete
a. save(E): It is insert operation when the primary key value is not available
in the database. (select + insert))
It is update operation when the primary key value is
available in the database. (select + update)
dao.saveAll(Arrays.asList(student1, student2));
a. findById(id): Returns the optional object of the entity you requested for.
System.out.println(dao.existsById(101));
System.out.println(dao.existsById(999));
System.out.println(dao.count());
Delete:
dao.deleteById(103);
HW: Develop the L3 and implement all 12 methods. Build one console based switch-
case application.
a. Insert
b. Update
c. Read
d. Delete
findBy methods:
The findBy methods in Spring Data JPA's CrudRepository enable query derivation
based on method names. This means that you can define methods in your repository
interface, and Spring will automatically generate the necessary query logic based
on the method's name. These methods follow a specific naming convention to create
queries dynamically, allowing you to perform database operations without explicitly
writing query code. This is called DSL (Domain Specific Language).
• findBy: This is the keyword indicating that you want to retrieve entities
from the database.
• <Property>: This refers to the field in your entity class that you want to
query by. The field name must match an attribute in your entity.
• [Optional Keyword]: You can add keywords like And, Or, Between, LessThan,
Like, etc., to build more complex queries.
Query Derivation Keywords
And
Or
Between
LessThan
findByAgeLessThan(int age)
GreaterThan
findByAgeGreaterThan(int age)
Like
findByEmailLike(String email)
OrderBy
findByLastNameOrderByFirstNameAsc(String lastName)
findByLastNameNot(String lastName)
IsNull
findByEmailIsNull()
IsNotNull
findByEmailIsNotNull()
True/False
findByActiveTrue() / findByActiveFalse()
Custom Query:
1. Using SQL
2. Using JPQL
Note #1:
If you are executing native SQL you must provide nativeQuery = true.
If you are executing JPQL / HQL by default it is false.
Note #2:
By default it will call executeQuery() method. That's why if you are giving non-
select query, it will through you the Exception.
@Modifying:
This annotation works for @Query. It tells the @Query that the given query is non-
select.
So it will use executeUpdate() method. That's why it's return type is Integer.
@Transactional:
Our Data JPA uses Hibernate. In Hibernate, every update operation happens inside
the transaction. That's why here also every non-select query you must execute as a
transaction.
This annotation handles the given query as a transaction.
JPQL:
1. Select Query
2. Update/Delete Query
3. Parameters: It supports both positional and named parameter
Positional Placeholder:
JPQL: FROM Book b WHERE b.bookName=?1
Named Parameter:
JPQL: FROM Book b WHERE b.bookName=:name
Note: You can map the method argument with the JPQL parameter name using @Param
Note: In JPQL also, if you are trying to execute any non-select query, you have to
use @Modifying and @Transactional
JPQL vs SQL:
#1:
JPQL is DB independent
SQL is DB dependent
#2:
JPQL follows the Java Entity.
SQL follows DB Table.
#3:
Performance wise SQL is better.
Maintenance wise JPQL is better.
#4:
SQL can directly execute in DB
JPQL can't directly execute in DB
ListCrudRepository:
1. saveAll()
2. findAll()
3. findAllById()
PagingAndSortingRepository:
::Sorting::
findAll(Sort sort)
1. Sort.by(properties[])
Order.by(property)
Order.asc(property)
Order.desc(property)
2. Sort.by(Order[])
3. Sort.by(List<Order>)
4. Sort.by(Direction.DESC, properties[])
::Paging::
If we are retrieving the records from the table as a page one by one and each page
contains a limited or pre-defined number of rows. The technique is called paging.
--Page--
Iterable
Streamable
Slice
Page
--Pageable--
PageRequest.ofSize(int pageSize)
PageRequest.of(0, 2)
PageRequest.of(1, 5)
HW:
Problem:
Find All entities of user table where first_name is 'David'
Solution:
List<User> findAllByFirstName(String firstName)
Now, assume you have so many properties in your Entity class. In the same way you
want to define the methods like:
findAllByFirstName
findAllByLastName
findAllByEmail
findAllByAge
findAllByActive
findAllByFirstNameAndLastName
...
For n non-primary key properties, you have to create: nC1 + nC2 + ... + nCn
QueryByExampleExecutor:
You can go for this approach when you want to generate the query dynamically
depending on the situation.
methods:
findOne(Example example)
findAll(Example example)
findAll(Example example, Sort sort)
findAll(Example example, Pageable pageable)
--Example--
of(probe)
of(probe, ExampleMatcher)
--ExampleMatcher--
matching()
matchingAny() [Checks for any of the given property in
example is matching or not. So, it is OR operation]
matchingAll() ---> Default [Checks for all of the given property in example is
matching or not. So, it is AND operation]
JpaRepository:
getReferenceById():
It just return you the reference to the entity (row). It don't give the
understandable information.
When you are required to get a particular reference of any entity object (row) for
any other query.
You can also use this reference to get a small amount of data.
This small data must be related to your @Id property.
@Entity
@Id
@Query
@Modifying
@Transactional
@Param
@NoReposioryBean
Create a sub dto class of your entity class. make this class as return type.
Utility Annotations:
@Entity
@Table(name = "table_name")
@Column(name = "column_name")
TimeStamping:
It is used to insert CREATED_DATE & UPDATED_DATE columns values for the record
Generators:
Enq_Id_Gen
next_val
0
+--------+
| enq_id |
+--------+
| 001 |
| 002 |
| 052 |
| 102 |
| 152 |
| 202 |
| 252 |
| 302 |
+--------+
generation strategies:
IDENTITY (AI)
SEQUENCE (Sequence)
TABLE (Separate Table)
AUTO
Custom Generators:
Example:
OD001
OD002
OD003
prefix + suffix
prefix = "OD"
suffix = AI
Interface: IdentifierGenerator
method: void generate()
-----------------------------------------------------------------------------------
----------------------------------------------------------------
public class EnquirySequenceGenerator implements IdentifierGenerator {
Connection con;
Statement st;
try {
con = session.getJdbcConnectionAccess().obtainConnection();
st = con.createStatement();
st.executeUpdate(query1);
st.executeUpdate(query2);
} catch (SQLException e) {
// ignore
}
@Override
public Serializable generate(SharedSessionContractImplementor session, Object
object) {
init(session);
ResultSet rs = st.executeQuery(query1);
if (rs.next()) {
suffix = String.format("%010d", rs.getInt(1));
}
st.executeUpdate(query2);
} catch (SQLException e) {
e.printStackTrace();
}
}
-----------------------------------------------------------------------------------
----------------------------------------------------------------
@Basic(optional = false)
@Column(nullable = false)
HW:
1. self join
2. inner join
3. left outer join
4. right outer join
1. One to One
2. One to Many
3. Many to Many
One to One:
--------------------------------------------------Entity
1--------------------------------------------------
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String username;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "profile_id", referencedColumnName = "id")
private Profile profile;
--------------------------------------------------Entity
2--------------------------------------------------
@Entity
public class Profile {
@Id
private Integer id;
private String name;
private Double age;
Note:
@JoinColumn is used to specify that the specific column is required to store the
foreign key. And it is not a simple column.
foreign key column default name: {@JoinColumn}_{@Id}
cascading:
profile.setId(101);
profile.setName("David Jones");
profile.setAge(36.0);
user.setUsername("david@123");
user.setProfile(profile);
repo.save(user);
One to Many:
--------------------------------------------------Entity
1--------------------------------------------------
@Entity
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn
private Department department;
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + "]";
}
--------------------------------------------------Entity
2--------------------------------------------------
@Entity
public class Department {
@Id
private Integer id;
@Override
public String toString() {
return "Department [id=" + id + ", name=" + name + ", employees=" +
employees + "]";
}
Note:
--------------------------------------------------Many-To-One-
Test--------------------------------------------------
@Autowired
private EmployeeRepo repo;
repo.saveAll(List.of(employee1, employee2));
--------------------------------------------------One-To-Many-
Test--------------------------------------------------
@Autowired
private DepartmentRepo repo;
}
Many to Many
In this relationship, one entity can relate to multiple entities and vice versa.
Example: Relation between Student & Course
--------------------------------------------------Entity
1--------------------------------------------------
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@ManyToMany
@JoinTable( // define a (bridge) new table for join
name = "student_course", // name of the join table
joinColumns = @JoinColumn(name = "student_id"), // Foreign key to student
table
inverseJoinColumns = @JoinColumn(name = "course_id") // Foreign key to
course table
)
private Set<Course> courses;
--------------------------------------------------Entity
2--------------------------------------------------
@Entity
public class Course {
@Id
private Long id;
Note:
By using @JoinTable we want to create a new bridge table for the two entities and
we can also specify the table configuration by providing the values.
--------------------------------------------------Many-To-Many-
Test--------------------------------------------------
Saving a Student and Course
@Autowired
private StudentRepo repo;
// course1.setStudents(Set.of(student));
repo.save(student);
Note: Cross Join can not be implemented in Data JPA. You can use native query.
Remaining Topic:
Conclusion: