Basic CRUD Operations¶
Learn how to perform Create, Read, Update, and Delete operations using Zygarde's generated DAOs.
Entity Setup¶
First, define your entity with @ZyModel:
@Entity
@Table(name = "users")
@ZyModel
data class User(
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long? = null,
@Column(nullable = false)
val username: String,
@Column(nullable = false)
val email: String,
val fullName: String? = null,
val active: Boolean = true,
@Column(name = "created_at")
val createdAt: LocalDateTime = LocalDateTime.now()
) : AutoLongIdEntity()
After building, Zygarde generates UserDao and search DSL.
Create Operations¶
Single Entity¶
@Service
class UserService(private val dao: Dao) {
@Transactional
fun createUser(username: String, email: String): User {
val user = User(
username = username,
email = email,
fullName = null
)
return dao.user.save(user)
}
}
Batch Creation¶
@Transactional
fun createUsers(userRequests: List<CreateUserRequest>): List<User> {
val users = userRequests.map { req ->
User(
username = req.username,
email = req.email,
fullName = req.fullName
)
}
return dao.user.saveAll(users)
}
Read Operations¶
Find by ID¶
fun getUserById(id: Long): User? {
return dao.user.findById(id).orElse(null)
}
// Or with exception
fun getUserByIdOrThrow(id: Long): User {
return dao.user.findById(id)
.orElseThrow { NotFoundException("User not found: $id") }
}
Find All¶
fun getAllUsers(): List<User> {
return dao.user.findAll()
}
// With pagination
fun getUsersPaged(page: Int, size: Int): Page<User> {
val pageable = PageRequest.of(page, size, Sort.by("createdAt").descending())
return dao.user.findAll(pageable)
}
Search with Criteria¶
fun findActiveUsers(): List<User> {
return dao.user.search {
active() eq true
}
}
fun findUserByEmail(email: String): User? {
return dao.user.search {
email() eq email
}.firstOrNull()
}
fun searchUsersByName(keyword: String): List<User> {
return dao.user.search {
or {
username() containsIgnoreCase keyword
fullName() containsIgnoreCase keyword
}
}
}
Update Operations¶
Update Single Field¶
@Transactional
fun deactivateUser(id: Long): User? {
val user = dao.user.findById(id).orElse(null) ?: return null
val updated = user.copy(active = false)
return dao.user.save(updated)
}
Update Multiple Fields¶
@Transactional
fun updateUserProfile(id: Long, request: UpdateProfileRequest): User? {
val user = dao.user.findById(id).orElse(null) ?: return null
val updated = user.copy(
fullName = request.fullName,
email = request.email
)
return dao.user.save(updated)
}
Batch Update¶
@Transactional
fun activateMultipleUsers(userIds: List<Long>) {
val users = dao.user.findAllById(userIds)
val activatedUsers = users.map { it.copy(active = true) }
dao.user.saveAll(activatedUsers)
}
Delete Operations¶
Delete by ID¶
@Transactional
fun deleteUser(id: Long) {
dao.user.deleteById(id)
}
// With existence check
@Transactional
fun deleteUserIfExists(id: Long): Boolean {
if (dao.user.existsById(id)) {
dao.user.deleteById(id)
return true
}
return false
}
Delete by Entity¶
Delete with Criteria (Enhanced DAO)¶
If using ZygardeEnhancedDao:
@Transactional
fun deleteInactiveUsers() {
dao.user.remove {
active() eq false
}
}
@Transactional
fun deleteUsersByDomain(domain: String) {
dao.user.remove {
email() like "%@$domain"
}
}
Batch Delete¶
Checking Existence¶
By ID¶
By Criteria¶
fun emailExists(email: String): Boolean {
return dao.user.search {
email() eq email
}.isNotEmpty()
}
fun usernameAvailable(username: String): Boolean {
return dao.user.search {
username() eq username
}.isEmpty()
}
Counting¶
Count All¶
Count with Criteria (Enhanced DAO)¶
fun countActiveUsers(): Int {
return dao.user.count {
active() eq true
}
}
fun countUsersByDomain(domain: String): Int {
return dao.user.count {
email() like "%@$domain"
}
}
Complete Service Example¶
@Service
class UserService(private val dao: Dao) {
@Transactional
fun createUser(request: CreateUserRequest): User {
// Check if email exists
val emailExists = dao.user.search {
email() eq request.email
}.isNotEmpty()
if (emailExists) {
throw BusinessException("Email already registered")
}
val user = User(
username = request.username,
email = request.email,
fullName = request.fullName
)
return dao.user.save(user)
}
fun getUserById(id: Long): User {
return dao.user.findById(id)
.orElseThrow { NotFoundException("User not found") }
}
fun searchUsers(query: String?, activeOnly: Boolean): List<User> {
return dao.user.search {
if (activeOnly) {
active() eq true
}
query?.let { keyword ->
or {
username() containsIgnoreCase keyword
fullName() containsIgnoreCase keyword
email() containsIgnoreCase keyword
}
}
}
}
@Transactional
fun updateUser(id: Long, request: UpdateUserRequest): User {
val user = getUserById(id)
val updated = user.copy(
fullName = request.fullName ?: user.fullName,
email = request.email ?: user.email
)
return dao.user.save(updated)
}
@Transactional
fun deactivateUser(id: Long): User {
val user = getUserById(id)
val deactivated = user.copy(active = false)
return dao.user.save(deactivated)
}
@Transactional
fun deleteUser(id: Long) {
if (!dao.user.existsById(id)) {
throw NotFoundException("User not found")
}
dao.user.deleteById(id)
}
}
Zygarde-Specific Tips¶
Leverage Search DSL¶
Use Zygarde's type-safe search DSL instead of manual criteria building:
// Zygarde way - readable and type-safe
dao.user.search {
active() eq true
createdAt() gte LocalDateTime.now().minusDays(7)
}
// Avoid verbose Criteria API or string-based queries
Validate Using Search DSL¶
Use Zygarde search for validation checks:
@Transactional
fun createUser(request: CreateUserRequest): User {
// Use search DSL for uniqueness check
if (dao.user.search { email() eq request.email }.isNotEmpty()) {
throw BusinessException("Email already exists")
}
return dao.user.save(User(/* ... */))
}
Next Steps¶
- Advanced Queries - Complex search patterns
- Relationships - Working with entity relationships
- Search DSL Guide - Complete DSL reference