我的用例:
我们有一个安装计划实体(检查下面的代码),它有一个安装日期。
安装完成后,我们将在4个工作日后与客户核实安装状态。 注意:(4 个工作日 - 此计数是可配置的。所以"X"工作日)
工作日是指 - 周一至周五。我们不关心其他假期。
- 我有一个调度程序,它会在"X"工作日后检索这些订单 -我被困在这里
我不知道如何在"X"工作日之后进行查询。
我的代码:
@Entity
@Table(schema = "myschema", name = "installation_dates")
@Getter
@Setter
@NoArgsConstructor
public class InstallDates extends TransEntity implements Serializable {
// other columns
@Column(name = "installation_schedule_datetime")
private LocalDateTime installationScheduleDatetime;//I use this column for calculation
@Formula("getWeekDaysCount(installationScheduleDatetime)")
private int weekDaysCount;
public int getWeekDaysCount(LocalDateTime installationScheduleDatetime) {
int totalWeekDays = 0;
LocalDateTime todayDate = LocalDateTime.now();
while (!installationScheduleDatetime.isAfter(todayDate)) {
switch (installationScheduleDatetime.getDayOfWeek()) {
case FRIDAY:
case SATURDAY:
break;
default:
totalWeekDays++;
break;
}
installationScheduleDatetime = installationScheduleDatetime.plusDays(1);
}
return totalWeekDays;
}
}
问题:
如何对工作日进行 SQL 或 JPQL 或 JPA 查询?
我知道它非常基本的问题,我是一名移动应用程序开发人员,我最近加入了Springboard团队,这对我来说真的很难:(
请随时提供您宝贵的反馈!
如果我正确解决了问题,我有以下建议。
爪哇岛:
- 以当前日期为准
- 找到
date of interest
:计数减去 4 个工作日(所以如果今天是星期五 - 减去 4 天,如果是星期一 - 周末减去 2 天,工作日再减 4 天)
然后编写一个查询,该查询将选择在感兴趣的日期完成的所有安装。 在伪代码中:select * from installations where installation_date = <date of interest>;
.
感兴趣的日期 Java 代码:
public LocalDateTime getDateOfInterest(int workdays) {
LocalDateTime currentDate = LocalDateTime.now();
if (workdays < 1) {
return currentDate;
}
//it will subtract 'X' working days from current date
LocalDateTime result = currentDate;
int addedDays = 0;
while (addedDays < workdays) {
result = result.minusDays(1);
if (!(result.getDayOfWeek() == DayOfWeek.FRIDAY ||
result.getDayOfWeek() == DayOfWeek.SATURDAY)) {
++addedDays;
}
}
return result;
}
首先让我们回答您的问题
- 不,您不能从
@Formula
调用方法 - 您可能可以(请参阅此处,但这可能取决于您的数据库。
使用实体和 JPA 的事实并不意味着所有内容都必须是 JPA 属性。
您可以:
- 编写一个动态计算它的 get 方法
- 写一个懒惰地设置它的 getter。
- 使用
@PostLoad
始终设置它。
@Entity
@Table(schema = "myschema", name = "installation_dates")
@Getter
@Setter
@NoArgsConstructor
public class InstallDates extends TransEntity implements Serializable {
// other columns
@Column(name = "installation_schedule_datetime")
private LocalDateTime installationScheduleDatetime;//I use this column for calculation
public int getWeekDaysCount() {
int totalWeekDays = 0;
LocalDateTime isdt = this.installationScheduleDatetime;
LocalDateTime todayDate = LocalDateTime.now();
while (!isdt.isAfter(todayDate)) {
switch (isdt.getDayOfWeek()) {
case FRIDAY:
case SATURDAY:
break;
default:
totalWeekDays++;
break;
}
isdt = isdt.plusDays(1);
}
return totalWeekDays;
}
}
或者,如果您真的希望它是一个属性,则可以使用 getter 懒惰地设置它。
@Entity
@Table(schema = "myschema", name = "installation_dates")
@Getter
@Setter
@NoArgsConstructor
public class InstallDates extends TransEntity implements Serializable {
// other columns
@Column(name = "installation_schedule_datetime")
private LocalDateTime installationScheduleDatetime;//I use this column for calculation
private int weekDaysCount = -1;
public int getWeekDaysCount() {
if (weekDaysCount == -1) {
int totalWeekDays = 0;
LocalDateTime isdt = this.installationScheduleDatetime;
LocalDateTime todayDate = LocalDateTime.now();
while (!isdt.isAfter(todayDate)) {
switch (isdt.getDayOfWeek()) {
case FRIDAY:
case SATURDAY:
break;
default:
totalWeekDays++;
break;
}
isdt = isdt.plusDays(1);
}
weekDaysCount = totalWeekDays;
}
return weekDaysCount;
}
}
或者,如果您总是想计算该值,您甚至可以将其放在方法的@PostLoad
注释中以初始化它(您甚至可以重用上面的惰性getter)。或者将 init 代码移动到@PostLoad
注释方法。
@PostLoad
private void initValues() {
getWeekDaysCount();
}
>@Formula
指定用本机SQL编写的表达式,该表达式用于读取属性的值,而不是将值存储在列中。(https://docs.jboss.org/hibernate/orm/current/javadocs/org/hibernate/annotations/Formula.html)
至于您的情况,如果weekDaysCount
是从installationScheduleDatetime
派生的,那么在数据库中存储似乎没有多大用处。我只是将weekDaysCount
标记为@Transient
并完成它(应该删除@Formula
)。
另一种解决方案是将weekDaysCount
保持非瞬态状态,并将计算置于@PreUpdate/@PrePersist
方法中。有关此内容的更多信息,请参阅 https://www.baeldung.com/jpa-entity-lifecycle-events。