使用 JPA 为多个报告查询具有不同复杂 where 子句的视图的最佳方法
Best way to query a view with different complex where clauses for multiple reports using JPA
我正在尝试想出一种基于相同基本实体实现多个报告页面的好方法。
想象一下,我想根据汽车的某些复杂属性生成多个报告 - 基本相同的 SELECT
和相同的 FROM
,但具有不同的复杂 WHERE
子句。
报告示例:
- R1:A品牌所有在B期到C期做检查,安装了D件,在E国使用的汽车清单。
- R2:今年生产的所有汽车列表
- ...
- R20:列表...
除此之外,我想要一个过滤组件来帮助查找特定案例。我们可以假设所有这些报告的过滤组件都是相同的,因为 fields/columns 对于所有报告都是(几乎)相同的。
最直接的解决方案是创建 20 个包含所有语句的视图,创建 20 个实体来映射这些数据库视图,并为所有这些视图创建存储库。但我想这可以通过更聪明的方式实现。
我最初的想法是创建一个基本实体 CarReportBaseEntity
,其中包含大约 50 fields/columns。
@Entity
@Table(name = "CAR_REPORT_VIEW")
public abstract class CarReportBaseEntity<T extends CarReportBaseEntity<T>> implements Serializable, FilteredEntity<T> {
@Id
@Column(insertable = false, updatable = false)
private Long id;
@Column(insertable = false, updatable = false)
private Long manufacturedYear;
etc...
}
然后对于每个不同的报告,我将创建一个实体,例如:
@Entity
@Where(clause = "manufacturedYear = 2020")
class ManufacturedIn2020ReportEntity extends CarReportBaseEntity<ManufacturedIn2020ReportEntity> {
}
其他报告也类似:
@Entity
@Where(clause = "some complex where clause")
class SomeOtherReportEntity extends CarReportBaseEntity<SomeOtherReportEntity> {
}
这将允许我通过添加一个 class 和调整 @Where
注释来快速创建新报告,包括 FilteredEntity
共享的所有功能。然而,这不起作用,因为它默认创建一个 @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
,然后破坏整个应用程序,因为我没有指定任何 DTYPE
列。我不想指定任何内容,我只想为同一个实体创建 classes,但具有不同的复杂 where 子句。
我该怎么做才能优雅地解决这个问题?
您只需要:
- 您已经拥有 CarReportBaseEntity
的实体 class
- 创建 20 个 CriteriaQueries 的工厂,其中包含每个报告的 jpa criateria
- 一堆获取 CriteriaQuery 参数并添加进一步过滤的(服务)方法(例如
whereCarBrandStartsWith(CriteriaQuery q, String prefix)
)
要获取报告,您需要获取该报告的 CriteriaQuery 对象,然后只获取该结果列表。如果您需要进一步过滤这些结果,您可以将条件对象传递给您想要的服务方法
编辑 1:
we would really benefit from multiple classes since then we could extend the FilterEntity with specific columns/order for each report case
您的条件查询不必总是 return CarReportBaseEntity。对于每个报告,您可以定义任何您想要的 select 子句 (CriteriaQuery::multiselect) and wrap the result in whatever dto you want (CriteriaBuilder::createQuery(resultType))。我在这种方法中看到的优势是您可以将所有查询逻辑保存在一个地方,在您的工厂中,而不是将其拆分为 20 个 classes 和许多注释之一。
我正在尝试想出一种基于相同基本实体实现多个报告页面的好方法。
想象一下,我想根据汽车的某些复杂属性生成多个报告 - 基本相同的 SELECT
和相同的 FROM
,但具有不同的复杂 WHERE
子句。
报告示例:
- R1:A品牌所有在B期到C期做检查,安装了D件,在E国使用的汽车清单。
- R2:今年生产的所有汽车列表
- ...
- R20:列表...
除此之外,我想要一个过滤组件来帮助查找特定案例。我们可以假设所有这些报告的过滤组件都是相同的,因为 fields/columns 对于所有报告都是(几乎)相同的。
最直接的解决方案是创建 20 个包含所有语句的视图,创建 20 个实体来映射这些数据库视图,并为所有这些视图创建存储库。但我想这可以通过更聪明的方式实现。
我最初的想法是创建一个基本实体 CarReportBaseEntity
,其中包含大约 50 fields/columns。
@Entity
@Table(name = "CAR_REPORT_VIEW")
public abstract class CarReportBaseEntity<T extends CarReportBaseEntity<T>> implements Serializable, FilteredEntity<T> {
@Id
@Column(insertable = false, updatable = false)
private Long id;
@Column(insertable = false, updatable = false)
private Long manufacturedYear;
etc...
}
然后对于每个不同的报告,我将创建一个实体,例如:
@Entity
@Where(clause = "manufacturedYear = 2020")
class ManufacturedIn2020ReportEntity extends CarReportBaseEntity<ManufacturedIn2020ReportEntity> {
}
其他报告也类似:
@Entity
@Where(clause = "some complex where clause")
class SomeOtherReportEntity extends CarReportBaseEntity<SomeOtherReportEntity> {
}
这将允许我通过添加一个 class 和调整 @Where
注释来快速创建新报告,包括 FilteredEntity
共享的所有功能。然而,这不起作用,因为它默认创建一个 @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
,然后破坏整个应用程序,因为我没有指定任何 DTYPE
列。我不想指定任何内容,我只想为同一个实体创建 classes,但具有不同的复杂 where 子句。
我该怎么做才能优雅地解决这个问题?
您只需要:
- 您已经拥有 CarReportBaseEntity 的实体 class
- 创建 20 个 CriteriaQueries 的工厂,其中包含每个报告的 jpa criateria
- 一堆获取 CriteriaQuery 参数并添加进一步过滤的(服务)方法(例如
whereCarBrandStartsWith(CriteriaQuery q, String prefix)
)
要获取报告,您需要获取该报告的 CriteriaQuery 对象,然后只获取该结果列表。如果您需要进一步过滤这些结果,您可以将条件对象传递给您想要的服务方法
编辑 1:
we would really benefit from multiple classes since then we could extend the FilterEntity with specific columns/order for each report case
您的条件查询不必总是 return CarReportBaseEntity。对于每个报告,您可以定义任何您想要的 select 子句 (CriteriaQuery::multiselect) and wrap the result in whatever dto you want (CriteriaBuilder::createQuery(resultType))。我在这种方法中看到的优势是您可以将所有查询逻辑保存在一个地方,在您的工厂中,而不是将其拆分为 20 个 classes 和许多注释之一。