如何使用 springframework.data.jpa.repository.Query 查找两个日期之间忽略时间的所有结果
How to use springframework.data.jpa.repository.Query to find all results between two dates ignoring time
我正在为如此简单的任务而苦苦挣扎,但我不知道自己做错了什么。
根据个人研究,我似乎正在编写我应该编写的代码,以便使用 Spring 数据搜索两个日期之间的所有记录。据我所知,“@Temporal(TemporalType.DATE)”发挥了“魔力”。
存储库
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import javax.persistence.TemporalType;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.jpa.repository.Temporal;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import com.mybank.accountmanagement.model.Transaction;
@Repository
public interface TransactionRepository extends JpaRepository<Transaction, Long> {
@Query(value = "SELECT * FROM transactions WHERE account_id=:idAccount AND CAST(created_at AS date) BETWEEN :fromDate AND :toDate ", nativeQuery = true)
List<Transaction> findByAccountIdWithCreationDateBetween(@Param("idAccount") Long idAccount,
@Param("fromDate") @Temporal(TemporalType.DATE) Date fromDate,
@Param("toDate") @Temporal(TemporalType.DATE) Date toDate);
}
型号:
交易
package com.mybank.accountmanagement.model;
import java.math.BigDecimal;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
import org.springframework.format.annotation.NumberFormat;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonIdentityReference;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
@Entity
@Table(name = "transactions")
public class Transaction extends AuditModel {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "account_id", nullable = false)
@OnDelete(action = OnDeleteAction.CASCADE)
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
@JsonIdentityReference(alwaysAsId = true)
@JsonProperty("accoout_id")
private Account account;
@NotNull
@NumberFormat(pattern = "#,###,###,###.##")
private BigDecimal amount;
@NotNull
private int transactionType;
public Transaction(Account account, @NotNull BigDecimal amount, @NotNull int transactionType) {
super();
this.account = account;
this.amount = amount;
this.transactionType = transactionType;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
public int getTransactionType() {
return transactionType;
}
public void setTransactionType(int transactionType) {
this.transactionType = transactionType;
}
}
审计模型
package com.mybank.accountmanagement.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
@JsonIgnoreProperties(value = { "createdAt", "updatedAt" }, allowGetters = true)
public abstract class AuditModel implements Serializable {
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "created_at", nullable = false, updatable = false)
@CreatedDate
private Date createdAt;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "updated_at", nullable = false)
@LastModifiedDate
private Date updatedAt;
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public Date getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(Date updatedAt) {
this.updatedAt = updatedAt;
}
}
我在使用“fromDate”:“2020-08-02”、“toDate”:“2020-08-02”搜索时 return 的期望
但是return根本没有记录
*** 已编辑
由于某些未知原因,我的准确日期匹配 fromDate 和 toDate 的记录从结果中删除了标记
搜索更长的 fromDate 和 toDate
curl --location --request GET 'localhost:2000/transaction/1/bankstatement' --header 'Content-Type: application/json' --data-raw '{
"fromDate":"2020-08-01",
“截止日期”:“2020-08-03”
}'
带来两条记录:
[
{
"createdAt": "2020-08-02T16:29:08.085+00:00",
"updatedAt": "2020-08-02T16:29:08.085+00:00",
"id": 1,
"amount": 1.00,
"transactionType": 2,
"accoout_id": 1
},
{
"createdAt": "2020-08-02T16:29:11.185+00:00",
"updatedAt": "2020-08-02T16:29:11.185+00:00",
"id": 2,
"amount": 2.00,
"transactionType": 1,
"accoout_id": 1
}
]
到目前为止一切顺利
现在我在搜索确切日期时遇到问题。我希望上述查询的结果相同
curl --location --request GET 'localhost:2000/transaction/1/bankstatement' --header 'Content-Type: application/json' --data-raw '{
“从日期”:“2020-08-02”,
“截止日期”:“2020-08-02”
}'
根本没有结果
*** 已编辑。多亏了 Kavithakaran Kanapathippillai 提供的示例,我注意到它适用于新日期或 2020-08-02T00:00:00.000+00:00,但在 2020-08-02 时失败。我仍然不知道为什么它会在 2020-08-02 失败,因为我不在乎时间,而且如果少尝试一天它也会起作用:2020-08-01
控制器
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.mybank.accountmanagement.BankStatementFilter;
import com.mybank.accountmanagement.model.Transaction;
import com.mybank.accountmanagement.repository.TransactionRepository;
import com.mybank.accountmanagement.service.TransactionService;
@RestController
public class TransactionController {
@Autowired
TransactionService transactionService;
@Autowired
TransactionRepository transactionRepository;
@GetMapping("/transaction/{accountId}/bankstatement")
public List<Transaction> bankStatement(@PathVariable(value = "accountId") Long accountId,
@Valid @RequestBody BankStatementFilter bankStatementFilter) {
return transactionRepository.findByAccountIdWithCreationDateBetween(accountId,
bankStatementFilter.getFromDate(), bankStatementFilter.getToDate());
}
}
一个简单的 Pojo,仅用于从客户端(例如 Postman 或 curl)发送的字符串中获取新日期
import java.util.Date;
public class BankStatementFilter {
private Date fromDate;
private Date toDate;
public Date getFromDate() {
return fromDate;
}
public void setFromDate(Date fromDate) {
this.fromDate = fromDate;
}
public Date getToDate() {
return toDate;
}
public void setToDate(Date toDate) {
this.toDate = toDate;
}
}
我用这个 POJO BankStatementFilter 做了一些愚蠢的事情
这是我在比较 new Date() 和 2020-08-02 时注意到的。既然我不在乎时间,那不是吗?
*** 最后评论
它正在工作。我将我的 POJO 更改为 bellow。如果我在做一些愚蠢的事情,我会感谢你的建议。顺便说一句,我原来的问题得到了 100% 的回答。
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class BankStatementFilter {
private Date fromDate;
private Date toDate;
public Date getFromDate() {
return fromDate;
}
public void setFromDate(String fromDate) {
String pattern = "yyyy-MM-dd";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
try {
this.fromDate = simpleDateFormat.parse(fromDate);
} catch (ParseException e) {
e.printStackTrace();
}
}
public Date getToDate() {
return toDate;
}
public void setToDate(String toDate) {
String pattern = "yyyy-MM-dd";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
try {
this.toDate = simpleDateFormat.parse(toDate);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
您是否尝试过在 SQL 查询中使用 >= 和 <=,在我的例子中,它按预期工作。
此外,我的建议是不要使用本机查询并尝试使用模型 class 在您的情况下进行快速正确的反序列化,因为您定义了模型 class。
@Temporal.Date
对您的 spring 数据存储方法没有任何影响。它只有在实体中被注释时才有影响。
而是对 cast
您的参数执行以下操作:
@Query(value = "SELECT * FROM transactions WHERE account_id=:idAccount " +
"AND CAST(created_at AS date) " +
"BETWEEN CAST(:fromDate AS date) AND CAST(:toDate AS date)"
, nativeQuery = true)
List<Transaction> findBy(@Param("idAccount") Long idAccount,
@Param("fromDate") Date fromDate,
@Param("toDate") Date toDate);
这是我与您的实体一起设置的示例项目,但 account
除外,因为如果您想比较,它不在问题范围内。您可以将项目作为 maven 导入 IntelliJ 和 运行 主应用程序,它将插入数据并将其带回
我正在为如此简单的任务而苦苦挣扎,但我不知道自己做错了什么。
根据个人研究,我似乎正在编写我应该编写的代码,以便使用 Spring 数据搜索两个日期之间的所有记录。据我所知,“@Temporal(TemporalType.DATE)”发挥了“魔力”。
存储库
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import javax.persistence.TemporalType;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.jpa.repository.Temporal;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import com.mybank.accountmanagement.model.Transaction;
@Repository
public interface TransactionRepository extends JpaRepository<Transaction, Long> {
@Query(value = "SELECT * FROM transactions WHERE account_id=:idAccount AND CAST(created_at AS date) BETWEEN :fromDate AND :toDate ", nativeQuery = true)
List<Transaction> findByAccountIdWithCreationDateBetween(@Param("idAccount") Long idAccount,
@Param("fromDate") @Temporal(TemporalType.DATE) Date fromDate,
@Param("toDate") @Temporal(TemporalType.DATE) Date toDate);
}
型号:
交易
package com.mybank.accountmanagement.model;
import java.math.BigDecimal;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
import org.springframework.format.annotation.NumberFormat;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonIdentityReference;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
@Entity
@Table(name = "transactions")
public class Transaction extends AuditModel {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "account_id", nullable = false)
@OnDelete(action = OnDeleteAction.CASCADE)
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
@JsonIdentityReference(alwaysAsId = true)
@JsonProperty("accoout_id")
private Account account;
@NotNull
@NumberFormat(pattern = "#,###,###,###.##")
private BigDecimal amount;
@NotNull
private int transactionType;
public Transaction(Account account, @NotNull BigDecimal amount, @NotNull int transactionType) {
super();
this.account = account;
this.amount = amount;
this.transactionType = transactionType;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
public int getTransactionType() {
return transactionType;
}
public void setTransactionType(int transactionType) {
this.transactionType = transactionType;
}
}
审计模型
package com.mybank.accountmanagement.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
@JsonIgnoreProperties(value = { "createdAt", "updatedAt" }, allowGetters = true)
public abstract class AuditModel implements Serializable {
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "created_at", nullable = false, updatable = false)
@CreatedDate
private Date createdAt;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "updated_at", nullable = false)
@LastModifiedDate
private Date updatedAt;
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public Date getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(Date updatedAt) {
this.updatedAt = updatedAt;
}
}
我在使用“fromDate”:“2020-08-02”、“toDate”:“2020-08-02”搜索时 return 的期望
但是return根本没有记录
*** 已编辑
由于某些未知原因,我的准确日期匹配 fromDate 和 toDate 的记录从结果中删除了标记
搜索更长的 fromDate 和 toDate
curl --location --request GET 'localhost:2000/transaction/1/bankstatement' --header 'Content-Type: application/json' --data-raw '{ "fromDate":"2020-08-01", “截止日期”:“2020-08-03” }'
带来两条记录:
[
{
"createdAt": "2020-08-02T16:29:08.085+00:00",
"updatedAt": "2020-08-02T16:29:08.085+00:00",
"id": 1,
"amount": 1.00,
"transactionType": 2,
"accoout_id": 1
},
{
"createdAt": "2020-08-02T16:29:11.185+00:00",
"updatedAt": "2020-08-02T16:29:11.185+00:00",
"id": 2,
"amount": 2.00,
"transactionType": 1,
"accoout_id": 1
}
]
到目前为止一切顺利
现在我在搜索确切日期时遇到问题。我希望上述查询的结果相同
curl --location --request GET 'localhost:2000/transaction/1/bankstatement' --header 'Content-Type: application/json' --data-raw '{ “从日期”:“2020-08-02”, “截止日期”:“2020-08-02” }'
根本没有结果
*** 已编辑。多亏了 Kavithakaran Kanapathippillai 提供的示例,我注意到它适用于新日期或 2020-08-02T00:00:00.000+00:00,但在 2020-08-02 时失败。我仍然不知道为什么它会在 2020-08-02 失败,因为我不在乎时间,而且如果少尝试一天它也会起作用:2020-08-01
控制器
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.mybank.accountmanagement.BankStatementFilter;
import com.mybank.accountmanagement.model.Transaction;
import com.mybank.accountmanagement.repository.TransactionRepository;
import com.mybank.accountmanagement.service.TransactionService;
@RestController
public class TransactionController {
@Autowired
TransactionService transactionService;
@Autowired
TransactionRepository transactionRepository;
@GetMapping("/transaction/{accountId}/bankstatement")
public List<Transaction> bankStatement(@PathVariable(value = "accountId") Long accountId,
@Valid @RequestBody BankStatementFilter bankStatementFilter) {
return transactionRepository.findByAccountIdWithCreationDateBetween(accountId,
bankStatementFilter.getFromDate(), bankStatementFilter.getToDate());
}
}
一个简单的 Pojo,仅用于从客户端(例如 Postman 或 curl)发送的字符串中获取新日期
import java.util.Date;
public class BankStatementFilter {
private Date fromDate;
private Date toDate;
public Date getFromDate() {
return fromDate;
}
public void setFromDate(Date fromDate) {
this.fromDate = fromDate;
}
public Date getToDate() {
return toDate;
}
public void setToDate(Date toDate) {
this.toDate = toDate;
}
}
我用这个 POJO BankStatementFilter 做了一些愚蠢的事情
这是我在比较 new Date() 和 2020-08-02 时注意到的。既然我不在乎时间,那不是吗?
*** 最后评论
它正在工作。我将我的 POJO 更改为 bellow。如果我在做一些愚蠢的事情,我会感谢你的建议。顺便说一句,我原来的问题得到了 100% 的回答。
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class BankStatementFilter {
private Date fromDate;
private Date toDate;
public Date getFromDate() {
return fromDate;
}
public void setFromDate(String fromDate) {
String pattern = "yyyy-MM-dd";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
try {
this.fromDate = simpleDateFormat.parse(fromDate);
} catch (ParseException e) {
e.printStackTrace();
}
}
public Date getToDate() {
return toDate;
}
public void setToDate(String toDate) {
String pattern = "yyyy-MM-dd";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
try {
this.toDate = simpleDateFormat.parse(toDate);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
您是否尝试过在 SQL 查询中使用 >= 和 <=,在我的例子中,它按预期工作。
此外,我的建议是不要使用本机查询并尝试使用模型 class 在您的情况下进行快速正确的反序列化,因为您定义了模型 class。
@Temporal.Date
对您的 spring 数据存储方法没有任何影响。它只有在实体中被注释时才有影响。而是对
cast
您的参数执行以下操作:
@Query(value = "SELECT * FROM transactions WHERE account_id=:idAccount " +
"AND CAST(created_at AS date) " +
"BETWEEN CAST(:fromDate AS date) AND CAST(:toDate AS date)"
, nativeQuery = true)
List<Transaction> findBy(@Param("idAccount") Long idAccount,
@Param("fromDate") Date fromDate,
@Param("toDate") Date toDate);
这是我与您的实体一起设置的示例项目,但
account
除外,因为如果您想比较,它不在问题范围内。您可以将项目作为 maven 导入 IntelliJ 和 运行 主应用程序,它将插入数据并将其带回