【Spring Boot】SpringDataJpa/集計関数等使用時に、新しいJavaBeansを作成するのではなく既存Entityを流用して実装してみた。

SpringDataJpa/集計処理使用時には、既存Entityではなく専用JavaBeansを作成して結果を格納するように推奨されているが（<a href="http://terasolunaorg.github.io/guideline/5.4.1.RELEASE/ja/ArchitectureInDetail/DataAccessDetail/DataAccessJpa.html#entityquery">TERASOLUNA 6.3.3.2. Entity以外のオブジェクトにQueryの取得結果を格納する方法</a>）、新しいクラスを都度作成するのも煩わしいので、既存のEntityで代替できないかを試してみた。結果はOKだった。

対策）
①EntityをSeirializableにする（JavaBeans化）。
②Entityに集計結果格納用フィールドを作成して、@Transient（永続化対象外フィールド指定）を付加する。
③Entityに集計結果格納用コンストラクタを追加する。

```Customer.java
package hello;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

import org.springframework.data.annotation.Transient;

import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@NoArgsConstructor
@Entity
public class Customer implements Serializable {

	private static final long serialVersionUID = 6631793395389093746L;

	@Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;
    private String firstName;
    private String lastName;
        
    @Transient
    private long count;
    
    public Customer(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
    
    public Customer(String lastName, long count) {
    	this.lastName = lastName;
    	this.count = count;
    }

    @Override
    public String toString() {
        return String.format(
            "Customer[id=%d, firstName='%s', lastName='%s, count=%d']",
                id, firstName, lastName, count);
    }

}
```
```CustomerRepository.java
package hello;

import java.util.List;

import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;

public interface CustomerRepository extends CrudRepository<Customer, Long> {

    List<Customer> findByLastName(String lastName);
    
    @Query(value ="SELECT NEW hello.Customer(cu.lastName, Count(cu.id)) FROM Customer cu GROUP BY cu.lastName")
    List<Customer> GroupByLastName();
    
}
```
```Application.java
package hello;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class Application {

	private static final Logger log = LoggerFactory.getLogger(Application.class);

	public static void main(String[] args) {
		SpringApplication.run(Application.class);
	}

	@Bean
	public CommandLineRunner demo(CustomerRepository repository) {
		return (args) -> {
			// save a couple of customers
			repository.save(new Customer("Jack", "Bauer"));
			repository.save(new Customer("Chloe", "O'Brian"));
			repository.save(new Customer("Kim", "Bauer"));
			repository.save(new Customer("David", "Palmer"));
			repository.save(new Customer("Michelle", "Dessler"));

			// fetch all customers
			log.info("Customers found with findAll():");
			log.info("-------------------------------");
			for (Customer customer : repository.findAll()) {
				log.info(customer.toString());
			}
			log.info("");

			// fetch an individual customer by ID
			repository.findById(1L)
				.ifPresent(customer -> {
					log.info("Customer found with findById(1L):");
					log.info("--------------------------------");
					log.info(customer.toString());
					log.info("");
				});

			// fetch customers by last name
			log.info("Customer found with findByLastName('Bauer'):");
			log.info("--------------------------------------------");
			repository.findByLastName("Bauer").forEach(bauer -> {
				log.info(bauer.toString());
			});
			log.info("");

			// Customers'Count GroupByLastName
			log.info("Customers'Count GroupByLastName with GroupByLastName():");
			log.info("--------------------------------------------");
			repository.GroupByLastName().forEach(lastName -> {
				log.info(lastName.toString());
			});
			log.info("");
		};
	}

}
```
```excution.log
info : Customers found with findAll():
info : -------------------------------
info : Customer[id=1, firstName='Jack', lastName='Bauer, count=0']
info : Customer[id=2, firstName='Chloe', lastName='O'Brian, count=0']
info : Customer[id=3, firstName='Kim', lastName='Bauer, count=0']
info : Customer[id=4, firstName='David', lastName='Palmer, count=0']
info : Customer[id=5, firstName='Michelle', lastName='Dessler, count=0']
info : 
info : Customer found with findById(1L):
info : --------------------------------
info : Customer[id=1, firstName='Jack', lastName='Bauer, count=0']
info : 
info : Customer found with findByLastName('Bauer'):
info : --------------------------------------------
info : Customer[id=1, firstName='Jack', lastName='Bauer, count=0']
info : Customer[id=3, firstName='Kim', lastName='Bauer, count=0']
info : 
info : Customers'Count GroupByLastName with GroupByLastName():
info : --------------------------------------------
info : Customer[id=null, firstName='null', lastName='Bauer, count=2']
info : Customer[id=null, firstName='null', lastName='O'Brian, count=1']
info : Customer[id=null, firstName='null', lastName='Palmer, count=1']
info : Customer[id=null, firstName='null', lastName='Dessler, count=1']
```

併せて、こちらも参照ください。
「<a href="https://qiita.com/Hisashi-Yamauchi/items/926dd1ad34ac6364286e">SpringDataJpa/集計関数等使用時に、new xxxClass()を使用しない方法を試してみた。</a>」