public class Transaction {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private LocalDateTime eventDate;
@Column(nullable = false)
private Integer amount;
@Enumerated(EnumType.STRING)
private TransactionAction action;
@Column(columnDefinition = "TEXT")
private String memo;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;
}
다음과 같이 거래 내역에 관련된 entity가 있습니다.
거래와 관련된 api들은 금액들을 통계, 총합하는 등 여러 추가적인 api들이 있을 수 있는데 이것들을 위해 transactionAmount라는 class를 만들어 transaction api에서 책임 분리 및 더욱 객체지향적으로 설계할 수 있습니다.
public class Transaction {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private LocalDateTime eventDate;
@Embedded
private TransactionAmount amount;
@Column(columnDefinition = "TEXT")
private String memo;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;
}
위와 같이 @Embedded를 사용하여 amount, action을 분리한 모습입니다.
@Getter
@Embeddable
@NoArgsConstructor(force = true)
public class TransactionAmount {
@Enumerated(EnumType.STRING)
private final TransactionAction action;
private final Long amount;
public TransactionAmount(Long amount, String action) {
this.amount = amount;
this.action = TransactionAction.valueOf(action);
}
public Long getAmount() {
return this.amount != null ? amount : 0;
}
}
분리된 transactionAmount class의 모습입니다. 해당 클래스에서는 @Embeddable을 명시해줘야합니다.
서비스 레이어에서도 활동하는 객체이기 때문에 final을 적용하여 필드의 추가적인 수정이 금지되어있으며 생성자에서도 강제성을 부여하여 작동하고있습니다.
@Query("""
SELECT new com.damo.server.domain.transaction.TransactionTotalAmount(
new com.damo.server.domain.transaction.entity.TransactionAmount(
SUM(CASE WHEN t.amount.action = 'GIVING' THEN t.amount.amount ELSE 0 END), 'GIVING'
),
new com.damo.server.domain.transaction.entity.TransactionAmount(
SUM(CASE WHEN t.amount.action = 'RECEIVING' THEN t.amount.amount ELSE 0 END), 'RECEIVING'
)
)
FROM Transaction t
LEFT JOIN FETCH Person p ON t.person.id = p.id
WHERE t.user.id = :userId
""")
TransactionTotalAmount findTotalAmount(@Param("userId") final Long userId);
분리로 인해 쿼리가 더러워졌는데 이건 이제 방법을 찾아야할 거 같습니다....