Coding Models, Representing Cardinalities, and Starting with JPA
Topics to be Covered¶
- Models
- Representing Cardinalities
- JPA Queries
- Inheritance Representation
Understanding Models¶
Key Concepts:¶
-
What Are Models?
- Models are the blueprint entities in an application whose data is stored in the database. They represent real-world objects or concepts within a specific domain, such as products in an e-commerce application or users in a social media platform.
- Each model typically corresponds to a database table, where the model's attributes are mapped to table columns.
-
Example in Product Service:
- Products: Represents items available for purchase, including attributes like
id
,name
,description
,price
, etc. - Category: Represents groups or classifications under which products are categorized, with attributes like
id
,name
, anddescription
.
- Products: Represents items available for purchase, including attributes like
-
Handling Deletion in Models:
- Soft Delete:
- Instead of permanently deleting a record from the database, a "soft delete" involves marking the record as deleted by setting an
isDeleted
flag totrue
. This approach is preferred in scenarios where data recovery is important, as it avoids permanent data loss. - Advantages:
- Data Integrity: Accidental deletions can be prevented. For instance, if a wrong SQL command deletes records, they can be restored by setting
isDeleted
back tofalse
. - Performance: Soft deletes are often faster than hard deletes because no rows are physically removed, thereby avoiding the overhead of row reorganization in the database.
- Data Integrity: Accidental deletions can be prevented. For instance, if a wrong SQL command deletes records, they can be restored by setting
- Hard Delete:
- A "hard delete" permanently removes the record from the database, making it irretrievable. This is straightforward but risky, especially in systems where data integrity is critical.
-
Common Attributes in Models:
- Every model typically has certain attributes that are common across different entities. These attributes help track the lifecycle of a record and manage its state:
- id: A unique identifier for each record, often automatically generated by the database.
- createdAt: A timestamp indicating when the record was first created.
- lastUpdatedAt: A timestamp showing the last time the record was updated.
- isDeleted: A boolean flag indicating whether the record has been soft-deleted.
- Every model typically has certain attributes that are common across different entities. These attributes help track the lifecycle of a record and manage its state:
-
Recommended Practice:
- It is recommended to create a
BaseModel
class that includes these common attributes. Every other model in the application can then inherit from thisBaseModel
. This not only ensures consistency across models but also reduces code redundancy.
- It is recommended to create a
Practical Implementation:¶
-
Setting Up the Development Environment:
- IDE Setup: Use IntelliJ IDEA or another preferred IDE for the implementation.
- Dependencies:
- Spring Data JDBC: To facilitate database interaction using JDBC.
- MySQL Driver: To connect the application with a MySQL database.
- Configuration:
- Add the necessary dependencies in the
pom.xml
file. - Configure
application.properties
with database connection details such as URL, username, and password. Refer to the guide here for step-by-step instructions.
- Add the necessary dependencies in the
- Database Setup:
- Create a MySQL database specifically for the Product Service.
- Create a database user with appropriate privileges, and grant all necessary permissions to this user.
- Model Annotations:
- Annotate the
Product
andCategory
classes with@Entity
to map them to database tables. - Annotate the
id
field in theBaseModel
class with@Id
to designate it as the primary key.
- Annotate the
-
Demonstration:
- Execution: Run the application to ensure it correctly generates the
products
andcategories
tables in the database using the Object-Relational Mapping (ORM) framework, Hibernate. - Error Handling: If errors occur, review the annotations and database configuration, guiding students through the debugging process.
- Execution: Run the application to ensure it correctly generates the
Cardinalities and Spring Framework¶
Conceptual Understanding:¶
-
What are Cardinalities?
- Cardinalities define the relationships between two entities in a database. Understanding these relationships is crucial when designing a relational database, as it dictates how tables interact with each other.
-
Types of Relationships:
- One to One (1:1):
- Each instance of entity A is associated with exactly one instance of entity B.
- Example: A
User
entity and its correspondingUserProfile
. Each user has exactly one profile, and each profile belongs to exactly one user.
- One to Many (1:m):
- One instance of entity A is associated with multiple instances of entity B.
- Example: A
Category
entity can have multipleProduct
entities. Each category can contain multiple products, but each product belongs to only one category.
- Many to One (m:1):
- Multiple instances of entity A are associated with a single instance of entity B.
- Example: Multiple
Product
entities can belong to oneCategory
entity.
- Many to Many (m:m):
- Multiple instances of entity A can be associated with multiple instances of entity B.
- Example: A
Student
entity and aCourse
entity. A student can enroll in multiple courses, and a course can have multiple students.
- One to One (1:1):
-
How to Represent Relationships:
- One to One:
- Typically represented by storing the primary key of one entity as a foreign key in the other entity.
- One to Many / Many to One:
- The foreign key of the 'one' side is stored on the 'many' side. For example, the
Category
ID is stored in theProduct
table.
- The foreign key of the 'one' side is stored on the 'many' side. For example, the
- Many to Many:
- A join table (or mapping table) is used to store the associations between the entities.
- One to One:
Practical Implementation:¶
-
Representing Cardinalities in Spring:
- Annotations:
- Use
@OneToOne
,@OneToMany
,@ManyToOne
, or@ManyToMany
annotations to define relationships between entities. - Example: For a
Product
class having a reference to aCategory
class, use@ManyToOne
to indicate that many products belong to one category.
- Use
- Annotations:
-
Handling Bidirectional Relationships:
- When defining relationships in both directions (e.g.,
Product
has aCategory
, andCategory
has a list ofProduct
), ensure that Spring understands this as the same relationship. - Use the
mappedBy
attribute to avoid creating duplicate relationships. - Example:
@ManyToOne @JoinColumn(name = "category_id") private Category category; @OneToMany(mappedBy = "category") private List<Product> products;
- When defining relationships in both directions (e.g.,
-
Managing Cascade Operations:
- CascadeType.PERSIST: Ensures that when saving a product, if the associated category does not exist, it will be created and persisted.
- CascadeType.REMOVE: When a category is deleted, all associated products are also deleted to maintain referential integrity.
- Example:
- In the
Category
class, usingCascadeType.REMOVE
will automatically delete all products when a category is deleted
- In the
Creating a New Product¶
Step-by-Step Implementation:¶
-
Creating Repository Interfaces:
- Purpose: Repository interfaces provide the abstraction layer for CRUD operations on the database.
- ProductRepository:
- Extend
JpaRepository<Product, Long>
, whereProduct
is the entity andLong
is the type of the primary key. - This interface will inherit methods for common database operations like
save
,findById
,delete
, etc. - CategoryRepository:
- Similarly, extend
JpaRepository<Category, Long>
to manage category entities.
-
Implementing the Service Layer:
- SelfProductService:
- Use constructor injection to inject
ProductRepository
andCategoryRepository
. - Example:
@Service public class SelfProductService { private final ProductRepository productRepository; private final CategoryRepository categoryRepository; @Autowired public SelfProductService(ProductRepository productRepository, CategoryRepository categoryRepository) { this.productRepository = productRepository; this.categoryRepository = categoryRepository; } }
-
Creating a New Product:
- Functionality:
- Implement a method
createProduct
that first checks whether the category already exists in the database. - If the category exists, the product is added to the existing category. If not, a new category is created and associated with the product.
- Implement a method
- Using CascadeType.PERSIST:
- Ensure that when a new product is saved, and its associated category does not exist, the category is created automatically.
- Example:
public Product createProduct(ProductDTO productDTO) { Category category = categoryRepository.findByName(productDTO.getCategoryName()) .orElse(new Category(productDTO.getCategoryName())); Product product = new Product(productDTO.getName(), productDTO.getPrice(), category); return productRepository.save(product); }
- Functionality: