java - 使用 Criteria API 加入实体,关系仅在拥有方定义
问题描述
我有来自两个模块的两个实体。
有一个device-core
包含实体的模块Device
:
@Entity
@Table(name = "devices")
public class Device extends AbstractAuditingEntity implements Serializable
{
@NotNull
@EmbeddedId
private DeviceIdentity identity;
// other properties, getters, setters, equals, hashCode, toString omitted
}
然后是retail
依赖device-core
并包含实体的模块POS
:
@Entity
@Table(name = "pos")
public class POS extends AbstractAuditingEntity implements Serializable
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@OneToOne
@JoinColumns({
@JoinColumn(name = "device_vendor", referencedColumnName = "vendor"),
@JoinColumn(name = "device_model", referencedColumnName = "model"),
@JoinColumn(name = "device_sn", referencedColumnName = "sn")
})
private Device device;
// other properties, getters, setters, equals, hashCode, toString omitted
}
如您所见,在拥有方的实体上POS
<->
Device
定义了一对一的关系 ( )。但是,由于模块甚至不知道实体存在
,因此没有提及侧面。POS
POS
Device
device-core
POS
不幸的是,我无法添加pos
与Device
using的关系@OneToOne(mappedBy="device")
,因为这会在device-core
and之间产生循环依赖retail
,更不用说模块必须在根本不存在模块device-core
的环境中工作。retail
我还尝试扩展Device
实体并创建ExtendedDevice
包含从to@OneToOne()
映射的实体,但这也不起作用,因为 Hibernate 将其注册为另一个实体并需要在旁边添加字段(我无法修改)或创建一个新的虚拟该表将仅包含一列(或 3,因为设备 ID 是复合键),我必须将设备 ID 复制到其中。它还会添加另一个完全不必要且毫无意义的连接。这不是可接受的黑客攻击。ExtendedDevice
POS
dtype
Device
ExtendedDevice
用例:我需要列出Device
s、左连接POS
和(可选)在POS
.
问题:虽然这可以使用 JQPL 完成,但我还没有找到使用 Criteria API 的方法。
这是一个问题,因为我需要根据请求参数动态添加谓词。
我设法想出的唯一解决方案是非常肮脏的 hack,包括像这样附加 JPQL:
String q = "SELECT d.identity, p.id, p.name, b.id, b.name, c.identity, c.name"
+ " FROM Device d"
+ " LEFT JOIN POS p ON d.identity = p.device" // how to do this using Criteria API?
+ " LEFT JOIN p.branch b"
+ " LEFT JOIN b.company c";
List<String> predicates = new ArrayList<>();
if (criteria.getVendor() != null)
predicates.add("lower(d.identity.vendor) LIKE lower(concat('%', :vendor, '%'))");
if (criteria.getModel() != null)
predicates.add("lower(d.identity.model) LIKE lower(concat('%', :model, '%'))");
if (criteria.getSerialNumber() != null)
predicates.add("lower(d.identity.serialNumber) LIKE lower(concat('%', :serialNumber, '%'))");
if (criteria.getPosName() != null)
predicates.add("lower(p.name) LIKE lower(concat('%', :posName, '%'))");
if (criteria.getBranchName() != null)
predicates.add("lower(b.name) LIKE lower(concat('%', :branchName, '%'))");
if (criteria.getCompanyName() != null)
predicates.add("lower(c.name) LIKE lower(concat('%', :companyName, '%'))");
if (predicates.size() > 0) {
q += " WHERE " + String.join(" AND ", predicates);
}
TypedQuery<Object[]> emQ = em.createQuery(q, Object[].class);
if (criteria.getVendor() != null)
emQ.setParameter("vendor", criteria.getVendor());
if (criteria.getModel() != null)
emQ.setParameter("model", criteria.getModel());
if (criteria.getSerialNumber() != null)
emQ.setParameter("serialNumber", criteria.getSerialNumber());
if (criteria.getPosName() != null)
emQ.setParameter("posName", criteria.getPosName());
if (criteria.getBranchName() != null)
emQ.setParameter("branchName", criteria.getBranchName());
if (criteria.getCompanyName() != null)
emQ.setParameter("companyName", criteria.getCompanyName());
我讨厌它。你讨厌它。每个人都应该讨厌它。太可怕了。它虽然有效。
现在的问题是:是否有更清洁的方法来实现这个相当标准的用例?
还是 Criteria API 根本不适合用于高度模块化的项目?
我应该考虑其他选择吗?
谢谢你的帮助!
解决方案
推荐阅读
- reporting-services - 不同报告服务器上的不同数字格式
- java - 当字符都具有相似的重复时,使用霍夫曼编码压缩文件?
- c# - 查询 DBLink 时 OracleDataAdapter 未填充 DataTable
- python-3.x - 重新循环直到找到所有匹配项,逻辑?
- javascript - 无法在 NetCore 2 上添加 ReactJS.NET
- netsuite - NetSuite - 保存的搜索 - 动态日期范围公式
- azure-resource-manager - 部署 ARM 模板时出现内部服务器错误
- cytoscape.js - 带有 Dagre 布局的 Cytoscape.js 可以绘制垂直树吗?
- java - Eclipselink 尝试在表中插入空值
- scala - 将 List[Any] 中的每个对象转换为特定类型?