Spring Data JPA Kapsamlı Rehber: 40 Pratik Senaryo ve Kod Örnekleri ile Veritabanı İşlemlerini Yönetme

Spring Data JPA Kapsamlı Kullanım Rehberi

Spring Data JPA Diagram

İçindekiler

  1. Basit bir varlık (entity) oluşturma
  2. Temel CRUD işlemleri için repository oluşturma
  3. Özel sorgu metodu ekleme
  4. Birden fazla koşulla sorgu
  5. LIKE operatörü kullanma
  6. Sıralama ile sorgu
  7. Sayfalandırma
  8. @Query anotasyonu ile özel SQL sorgusu
  9. Native SQL sorgusu
  10. İlişkili varlıklar (One-to-Many)
  11. Many-to-Many ilişki
  12. Derived query metodu ile ilişkili varlıkları sorgulama
  13. @Query ile JOIN kullanımı
  14. Toplu güncelleme işlemi
  15. Soft delete işlemi
  16. Specification kullanımı
  17. Projection kullanımı
  18. Auditing özelliğini kullanma
  19. İndeks oluşturma
  20. Composite key kullanımı
  21. @Transactional kullanımı
  22. Criteria API kullanımı
  23. Inheritance mapping (Single Table)
  24. Composite primary key with @IdClass
  25. @NamedQuery kullanımı
  26. @Converter ile özel tip dönüşümü
  27. @Formula kullanımı
  28. Dinamik native query
  29. @Version ile optimistic locking
  30. Custom repository implementasyonu
  31. @Embeddable ve @Embedded kullanımı
  32. @ElementCollection ile basit koleksiyonların yönetimi
  33. @EntityGraph ile fetch stratejisini özelleştirme
  34. @Lob ile büyük nesnelerin yönetimi
  35. @SQLDelete ve @Where ile soft delete implementasyonu
  36. @Filter ile dinamik filtreleme
  37. @JsonIgnore ile sonsuz döngüleri önleme
  38. Specification ile dinamik sorgu oluşturma
  39. @QueryHints ile cache kontrolü
  40. Stored procedure çağırma

Senaryo 1: Basit bir varlık (entity) oluşturma


@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String email;
    // Getter ve setter metodları
}
    

Senaryo 2: Temel CRUD işlemleri için repository oluşturma


public interface UserRepository extends JpaRepository<User, Long> {
}
    

Senaryo 3: Özel sorgu metodu ekleme


public interface UserRepository extends JpaRepository<User, Long> {
    List<User> findByName(String name);
}
    

Senaryo 4: Birden fazla koşulla sorgu


public interface UserRepository extends JpaRepository<User, Long> {
    List<User> findByNameAndEmail(String name, String email);
}
    

Senaryo 5: LIKE operatörü kullanma


public interface UserRepository extends JpaRepository<User, Long> {
    List<User> findByNameLike(String namePattern);
}
    

Senaryo 6: Sıralama ile sorgu


public interface UserRepository extends JpaRepository<User, Long> {
    List<User> findByNameOrderByEmailDesc(String name);
}
    

Senaryo 7: Sayfalandırma


public interface UserRepository extends JpaRepository<User, Long> {
    Page<User> findAll(Pageable pageable);
}
    

Senaryo 8: @Query anotasyonu ile özel SQL sorgusu


public interface UserRepository extends JpaRepository<User, Long> {
    @Query("SELECT u FROM User u WHERE u.email LIKE %:domain")
    List<User> findUsersWithEmailDomain(@Param("domain") String domain);
}
    

Senaryo 9: Native SQL sorgusu


public interface UserRepository extends JpaRepository<User, Long> {
    @Query(value = "SELECT * FROM users WHERE name = ?1", nativeQuery = true)
    List<User> findUsersByNameNative(String name);
}
    

Senaryo 10: İlişkili varlıklar (One-to-Many)


@Entity
public class Department {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    @OneToMany(mappedBy = "department")
    private List<User> users;
    // Getter ve setter metodları
}

@Entity
public class User {
    // ... diğer alanlar

    @ManyToOne
    @JoinColumn(name = "department_id")
    private Department department;
    // Getter ve setter metodları
}
    

Senaryo 11: Many-to-Many ilişki


@Entity
public class Project {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    @ManyToMany(mappedBy = "projects")
    private Set<User> users = new HashSet<>();
    // Getter ve setter metodları
}

@Entity
public class User {
    // ... diğer alanlar

    @ManyToMany
    @JoinTable(
        name = "user_project",
        joinColumns = @JoinColumn(name = "user_id"),
        inverseJoinColumns = @JoinColumn(name = "project_id")
    )
    private Set<Project> projects = new HashSet<>();
    // Getter ve setter metodları
}
    

Senaryo 12: Derived query metodu ile ilişkili varlıkları sorgulama


public interface UserRepository extends JpaRepository<User, Long> {
    List<User> findByProjectsName(String projectName);
}
    

Senaryo 13: @Query ile JOIN kullanımı


public interface UserRepository extends JpaRepository<User, Long> {
    @Query("SELECT u FROM User u JOIN u.department d WHERE d.name = :deptName")
    List<User> findUsersByDepartmentName(@Param("deptName") String departmentName);
}
    

Senaryo 14: Toplu güncelleme işlemi


public interface UserRepository extends JpaRepository<User, Long> {
    @Modifying
    @Query("UPDATE User u SET u.email = :newEmail WHERE u.id = :userId")
    int updateUserEmail(@Param("userId") Long userId, @Param("newEmail") String newEmail);
}
    

Senaryo 15: Soft delete işlemi


@Entity
public class User {
    // ... diğer alanlar
    private boolean isDeleted = false;
}

public interface UserRepository extends JpaRepository<User, Long> {
    List<User> findByIsDeletedFalse();
}
    

Senaryo 16: Specification kullanımı


public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {
}

public class UserSpecifications {
    public static Specification<User> hasNameLike(String name) {
        return (root, query, cb) -> cb.like(root.get("name"), "%" + name + "%");
    }

    public static Specification<User> isInDepartment(String departmentName) {
        return (root, query, cb) -> cb.equal(root.get("department").get("name"), departmentName);
    }
}

// Kullanımı:
// userRepository.findAll(Specification.where(hasNameLike("John")).and(isInDepartment("IT")));
    

Senaryo 17: Projection kullanımı


public interface UserNameProjection {
    String getName();
    String getEmail();
}

public interface UserRepository extends JpaRepository<User, Long> {
    List<UserNameProjection> findByDepartmentName(String departmentName);
}
    

Senaryo 18: Auditing özelliğini kullanma (devam)


@Entity
public class User extends Auditable {
    // ... diğer alanlar
}
    

Senaryo 19: İndeks oluşturma


@Entity
@Table(indexes = @Index(columnList = "email"))
public class User {
    // ... diğer alanlar
}
    

Senaryo 20: Composite key kullanımı


@Entity
public class BookAuthor {
    @EmbeddedId
    private BookAuthorId id;

    // Diğer alanlar ve metodlar
}

@Embeddable
public class BookAuthorId implements Serializable {
    private Long bookId;
    private Long authorId;

    // Constructors, equals, hashCode metodları
}
    

Senaryo 21: @Transactional kullanımı


@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    @Transactional
    public void updateUserAndProject(Long userId, String newEmail, String newProjectName) {
        User user = userRepository.findById(userId).orElseThrow(() -> new RuntimeException("User not found"));
        user.setEmail(newEmail);
        
        Project newProject = new Project();
        newProject.setName(newProjectName);
        user.getProjects().add(newProject);
        
        userRepository.save(user);
    }
}
    

Senaryo 22: Criteria API kullanımı


@Repository
public class UserRepositoryImpl implements UserRepositoryCustom {
    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public List<User> findUsersByComplexCriteria(String name, Integer minAge, String departmentName) {
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<User> query = cb.createQuery(User.class);
        Root<User> user = query.from(User.class);

        List<Predicate> predicates = new ArrayList<>();

        if (name != null) {
            predicates.add(cb.like(user.get("name"), "%" + name + "%"));
        }
        if (minAge != null) {
            predicates.add(cb.greaterThan(user.get("age"), minAge));
        }
        if (departmentName != null) {
            predicates.add(cb.equal(user.get("department").get("name"), departmentName));
        }

        query.where(predicates.toArray(new Predicate[0]));

        return entityManager.createQuery(query).getResultList();
    }
}
    

Senaryo 23: Inheritance mapping (Single Table)


@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "employee_type")
public abstract class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    // Getter ve setter metodları
}

@Entity
@DiscriminatorValue("MANAGER")
public class Manager extends Employee {
    private String department;
    // Getter ve setter metodları
}

@Entity
@DiscriminatorValue("DEVELOPER")
public class Developer extends Employee {
    private String programmingLanguage;
    // Getter ve setter metodları
}
    

Senaryo 24: Composite primary key with @IdClass


@Entity
@IdClass(OrderItemId.class)
public class OrderItem {
    @Id
    private Long orderId;
    
    @Id
    private Long productId;
    
    private int quantity;
    // Getter ve setter metodları
}

public class OrderItemId implements Serializable {
    private Long orderId;
    private Long productId;
    // Constructors, equals, hashCode metodları
}
    

Senaryo 25: @NamedQuery kullanımı


@Entity
@NamedQuery(name = "User.findByEmailDomain",
    query = "SELECT u FROM User u WHERE u.email LIKE :domain")
public class User {
    // ... diğer alanlar
}

public interface UserRepository extends JpaRepository<User, Long> {
    List<User> findByEmailDomain(@Param("domain") String domain);
}
    

Senaryo 26: @Converter ile özel tip dönüşümü


@Converter(autoApply = true)
public class BooleanToStringConverter implements AttributeConverter<Boolean, String> {
    @Override
    public String convertToDatabaseColumn(Boolean attribute) {
        return (attribute != null && attribute) ? "Y" : "N";
    }

    @Override
    public Boolean convertToEntityAttribute(String dbData) {
        return "Y".equals(dbData);
    }
}

@Entity
public class User {
    // ... diğer alanlar
    @Convert(converter = BooleanToStringConverter.class)
    private Boolean active;
}
    

Senaryo 27: @Formula kullanımı


@Entity
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private BigDecimal price;
    private BigDecimal taxRate;

    @Formula("price * tax_rate")
    private BigDecimal totalPrice;
    // Getter ve setter metodları
}
    

Senaryo 28: Dinamik native query


public interface ProductRepository extends JpaRepository<Product, Long> {
    @Query(nativeQuery = true)
    List<Product> findProductsByDynamicCriteria(@Param("sql") String sql);
}

// Kullanımı:
// String sql = "SELECT * FROM product WHERE category = 'Electronics' AND price < 1000;
// List<Product> products = productRepository.findProductsByDynamicCriteria(sql);
    

Senaryo 29: @Version ile optimistic locking


@Entity
public class Inventory {
    @Id
    private Long productId;
    private Integer quantity;
    
    @Version
    private Integer version;
    // Getter ve setter metodları
}
    

Senaryo 30: Custom repository implementasyonu


public interface UserRepositoryCustom {
    List<User> findUsersByComplexCriteria(String name, Integer minAge, String departmentName);
}

public interface UserRepository extends JpaRepository<User, Long>, UserRepositoryCustom {
}

public class UserRepositoryImpl implements UserRepositoryCustom {
    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public List<User> findUsersByComplexCriteria(String name, Integer minAge, String departmentName) {
        // Criteria API implementasyonu (Senaryo 22'deki gibi)
    }
}
    

Senaryo 31: @Embeddable ve @Embedded kullanımı


@Embeddable
public class Address {
    private String street;
    private String city;
    private String country;
    // Getter ve setter metodları
}

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    
    @Embedded
    private Address address;
    // Getter ve setter metodları
}
    

Senaryo 32: @ElementCollection ile basit koleksiyonların yönetimi


@Entity
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    
    @ElementCollection
    @CollectionTable(name = "product_category", joinColumns = @JoinColumn(name = "product_id"))
    @Column(name = "category")
    private Set<String> categories = new HashSet<>();
    // Getter ve setter metodları
}
    

Senaryo 33: @EntityGraph ile fetch stratejisini özelleştirme


@Entity
@NamedEntityGraph(name = "User.withProjects",
    attributeNodes = @NamedAttributeNode("projects")
)
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    
    @ManyToMany
    private Set<Project> projects = new HashSet<>();
    // Getter ve setter metodları
}

public interface UserRepository extends JpaRepository<User, Long> {
    @EntityGraph(value = "User.withProjects")
    List<User> findByName(String name);
}
    

Senaryo 34: @Lob ile büyük nesnelerin yönetimi


@Entity
public class Document {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    
    @Lob
    private byte[] content;
    // Getter ve setter metodları
}
    

Senaryo 35: @SQLDelete ve @Where ile soft delete implementasyonu


@Entity
@SQLDelete(sql = "UPDATE user SET deleted = true WHERE id = ?")
@Where(clause = "deleted = false")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private boolean deleted = false;
    // Getter ve setter metodları
}
    

Senaryo 36: @Filter ile dinamik filtreleme


@Entity
@FilterDef(name = "deletedProductFilter", parameters = @ParamDef(name = "isDeleted", type = "boolean"))
@Filter(name = "deletedProductFilter", condition = "deleted = :isDeleted")
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private boolean deleted = false;
    // Getter ve setter metodları
}

// Kullanımı:
// Session session = entityManager.unwrap(Session.class);
// session.enableFilter("deletedProductFilter").setParameter("isDeleted", false);
// List<Product> products = productRepository.findAll();
    

Senaryo 37: @JsonIgnore ile sonsuz döngüleri önleme


@Entity
public class Department {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    
    @OneToMany(mappedBy = "department")
    @JsonIgnore
    private List<User> users;
    // Getter ve setter metodları
}
    

Senaryo 38: Specification ile dinamik sorgu oluşturma


public class UserSpecification {
    public static Specification<User> hasNameLike(String name) {
        return (root, query, criteriaBuilder) ->
            criteriaBuilder.like(root.get("name"), "%" + name + "%");
    }
    
    public static Specification<User> isOlderThan(int age) {
        return (root, query, criteriaBuilder) ->
            criteriaBuilder.greaterThan(root.get("age"), age);
    }
}

// Kullanımı:
// userRepository.findAll(Specification.where(hasNameLike("John")).and(isOlderThan(30)));
    

Senaryo 39: @QueryHints ile cache kontrolü


public interface UserRepository extends JpaRepository<User, Long> {
    @QueryHints(value = { @QueryHint(name = "org.hibernate.cacheable", value = "true") })
    List<User> findByAgeGreaterThan(int age);
}
    

Senaryo 40: Stored procedure çağırma


@Entity
public class User {
    // ... diğer alanlar
}

public interface UserRepository extends JpaRepository<User, Long> {
    @Procedure(name = "calculate_user_score")
    Integer calculateUserScore(@Param("userId") Long userId);
}
    

Önemli Noktalar

  • @Embeddable ve @Embedded ile kompleks tiplerin gömülmesi.
  • @ElementCollection ile basit koleksiyonların yönetimi.
  • @EntityGraph ile ilişkili varlıkların yükleme stratejisini özelleştirme.
  • @Lob ile büyük nesnelerin (Large Objects) yönetimi.
  • @SQLDelete ve @Where ile soft delete implementasyonu.
  • @Filter ile dinamik filtreleme.
  • @JsonIgnore ile sonsuz döngüleri önleme (özellikle REST API'lerde faydalı).
  • Specification ile dinamik sorgu oluşturma.
  • @QueryHints ile cache kontrolü.
  • Stored procedure çağırma örneği.

Please Select Embedded Mode To Show The Comment System.*

Daha yeni Daha eski

نموذج الاتصال