16 Nisan 2020 Perşembe

SpringData Jdbc NamedParameterJdbcTemplate Sınıfı

Giriş
Parametre olarak :id gibi isimler kullanabilmeyi sağlar. Şöyle yaparız.
String TEMP_INSERT = "INSERT INTO test(x) VALUES (:x)";
Parametre Alanı
JDBCTemplate ile parametre alanı için "?" kullanılırken NamedParameterJdbcTemplate ile ":myfield" şeklinde isim verilen parametre alanları kullanılıyor.
Bazı örnekler şöyle
"INSERT INTO USERS(name, address, email)values(:name,:address,:email)"
"select * from users where record_id = :id"

constructor - DataSource
XML ile tanımlarken şöyle yaparız.
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
  destroy-method="close">
  <property name="url" value="jdbc:dburl" />
  <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
  <property name="username" value="username" /> 
  <property name="password" value="passworf" />
  <property name="removeAbandoned" value="true" />
  <property name="initialSize" value="30" />    
  <property name="maxActive" value="100" />
</bean>

<!-- DAO Bean which is causing issue -->
<bean id="nmdParameter" class="org.springframeowrk....NamedParameterJDBCTemplate"
 scope="singleton">
  <constructor-args ref="dataSource" />    
</bean>
Şöyle yaparız.
DataSource dataSource = ...;
NamedParameterJdbcTemplate jdbc =new NamedParameterJdbcTemplate(dataSource);
batchUpdate metodu
Örnek
Şöyle yaparız.
String insertSQL = "INSERT INTO invoices VALUES (:id, :exactIssueTime, 
:finalIssueTime, :issuer, :groupID)";
SqlParameterSource[] sqlParams = SqlParameterSourceUtils.createBatch(
  invoices.toArray());

int[] insertCounts = namedJdbcTemplate.batchUpdate(insertSQL, sqlParams);
Örnek
Şöyle yaparız.
String TEMP_INSERT = "INSERT INTO test(x) VALUES (:x)";

NamedParameterJdbcTemplate namedParameterJdbcTemplate = ...;

public int batchTestInsert(SqlParameterSource[] parameters) {
  return Arrays.stream(
            namedParameterJdbcTemplate.batchUpdate(TEMP_INSERT, parameters)
        ).sum();
}
query metodu
Örnek ver

queryForObject metodu - Map
Tek bir sonuç nesnesi döner.

Örnek
Şöyle yaparız.
String firstName = ...;

String sql = "select count(*) from T_ACTOR where first_name = :first_name";

Map<String, String> namedParameters = Collections.singletonMap("first_name",
  firstName);

int i = namedJdbcTemplate.queryForObject(sql, namedParameters,  Integer.class);
Örnek
Şöyle yaparız.
Integer count = namedParameterJdbcTemplate.queryForObject("SELECT COUNT(1) FROM test",
 new HashMap<String, Object>, Integer.class);
 //I pass empty HashMap since query doesn't need parameters
queryForObject metodu - SqlParameterSource
Java'da Generics kullanılmaya başlamadan önce bu metod kullanılırdı. Bu overload metodu kullanmamak lazım. Bu metod yerine Map alan overload halini kullanmak daha iyi.
Örnek
Şöyle yaparız.
public void isRecordExists(Date date){
  String sqlQuery=" select * from Dual where created_date=:date";
  
  MapSqlParameterSource parameters = new MapSqlParameterSource();
  parameters.addValue("date", date);
  namedParameterJdbcTemplate.queryForObject(sqlQuery, parameters, Integer.class);

}
Örnek
Şöyle yaparız.
String firstName = ...;

String sql = "select count(*) from T_ACTOR where first_name = :first_name";

SqlParameterSource namedParameters = new MapSqlParameterSource("first_name",
  firstName);

int i = namedJdbcTemplate.queryForObject(sql, namedParameters, Integer.class);
update metodu
Örnek ver


15 Nisan 2020 Çarşamba

SpringData JpaRepository İle Custom Method veya Custom Repository

Giriş
Custom metod bence sadece @Query anotasyonu yetersiz kaldığı zaman kullanılmalı. @Query ile çok şeyler yapılabiliyor.
1. SpringData JpaRepository ile @Query ve Join
2. SpringData JpaRepository ile @Query ve Join + Wheren In Clause
3. SpringData JpaRepository İle JpaSpecification yazısına taşıdım

Kullanım
1. Custom Repository arayüzümüzü ve içindeki custom metod imzasını tanımlarız.
2. Normal Spring Repository (ismi FooRepository olsun) sınıfını tanımlarız ama hem JpaRepository hem deCustom Repository arayüzden kalıtırız.
2. FooRepositoryImpl isimli bir sınıf tanımlarız ve Custom Repository arayüzdeki metodu gerçekleştiririz

Örnek
Şöyle yaparız. Burada önce repository arayüzümüzü hem JpaRespository'den hem de kendi sınıfımızdan kalıtıyoruz.
public interface AccountRepository 
  extends JpaRepository<Account, Long>, AccountRepositoryCustom { ... }

public interface AccountRepositoryCustom {
  public void customMethod();
}
Daha sonra kendi özel arayüzümüzdeki metodu gerçekleştiriyoruz. Şöyle yaparız
public class AccountRepositoryImpl implements AccountRepositoryCustom {

  @PersistenceContext
  private EntityManager em;

  public void customMethod() { 
    ...
    em.createQuery(yourCriteria);
    ...
  }
}
Burada sınıfımızın ismi AccountRepositoryImpl olmak zorunda. Açıklaması şöyle.
For >= 2.0 the implementation has to be named as the custom interface with an additional Impl suffix.
Örnek
Şöyle yaparız
//Custom Repository with custom method
public interface EmployeeCustomizedRepository {
  List<Employee> getUserWithCustomQuery();
}

// Spring Repository inherits from JpaRepository + Custom Repository
@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Integer>, 
  EmployeeCustomizedRepository {

  List<Employee> findUserByLastName(String lastname);
  List<Employee> findUserByFistName(String firstname);
}

//Repository implementation with custom method
public class EmployeeCustomizedRepositoryImpl implements EmployeeCustomizedRepository {
	
  @PersistenceContext
  private EntityManager entityManager;

  @Override
  public List<Employee> getUserWithCustomQuery() {
    List<Employee> userList = entityManager
      .createQuery("Select e from Employee e")
      .getResultList();
    // Do the necessary tasks
    return userList;
  }
}
Şeklen şöyle



SpringData JpaRepository ile @Query ve Join - OneToMany Tarzı İlişkilerde Kullanılır

Giriş
Normal JPQL sorgusu yazıyoruz. Bu yöntem bence custom method eklemekten daha kolay.

Bu sorgularda dikkat edilmesi gereken şeyler şöyle
1. Join ile her zaman alias kullanmak gerekir.
2. Positional parameter kullanmak istersek =?1 gibi yazmak gerekir.
3. Parametre ismini kullamak istersek =:myparameter gibi yazmak gerekir.
Örnek - inner join
Şöyle yaparız.
@Query("select w from Way w join w.relations r where r.relationID=?1")
List<Way> selectAllWaysByRelationID(Long relationID);
Açıklaması şöyle.
When using JOIN you need to use alias of Way with relations field like this, w.relations r instead of Way.relations.

Örnek - LEFT JOIN FETCH
Place ->has -> City -> has -> State ilişkisi olsun. Şöyle yaparız.
public interface PlaceRepository extends
 JpaRepository<Place, Long>, PlaceRepositoryCustom {

  @Query(value = "SELECT p FROM Place p LEFT JOIN FETCH p.author
                  LEFT JOIN FETCH p.city c LEFT JOIN FETCH c.state 
                  where p.id = :id")
  Place findById(@Param("id") int id);
}

public interface CityRepository extends JpaRepository<City, Long>,
 CityRepositoryCustom { 
  @Query(value = "SELECT c FROM City c LEFT JOIN FETCH c.state where c.id = :id")
  City findById(@Param("id") int id);
}