【发布时间】:2022-01-28 11:03:41
【问题描述】:
我正在尝试使用联接执行 SQL 查询,其中联接具有附加过滤条件。使用纯 SQL,我的数据建模如下:
create table food_storage (
name varchar primary key
);
create table food (
name varchar primary key,
expired bool,
stored_in varchar references food_storage(name)
);
insert into food_storage (name) values ('drawer'), ('fridge'), ('cabinet');
insert into food
(name, expired, stored_in)
values
('teabags', false, 'drawer'),
('beans', true, 'drawer'),
('leftovers', true, 'fridge'),
('rice', false, 'cabinet'),
('flour', false, 'cabinet');
我的查询看起来像这样(为简洁起见,只选择了几个字段):
select food_storage.name, food.name from food_storage
left outer join food on food.stored_in = food_storage.name and not food.expired;
| name | name |
|---|---|
| drawer | teabags |
| cabinet | rice |
| cabinet | flour |
| fridge | (null) |
但是,我正在尝试使用 JPA 执行此查询,并将结果成功映射回 JPA 实体。我这样建模我的 JPA 实体:
@Entity
@Table(name = "food_storage")
@Data
public class FoodStorage {
@Id
private String name;
@OneToMany(mappedBy = "stored_in")
private List<Food> foodContents;
}
@Entity
@Table(name = "food")
@Data
public class Food {
@Id
private String name;
@Column
private boolean expired;
@Column(name = "stored_in")
private String storedIn;
}
对于上面的原始 SQL 查询结果,我需要将结果映射回如下实体:
[
FoodStorage(name=drawer, foodContents=[
Food(name=teabags, expired=false, storedIn=drawer)
]),
FoodStorage(name=fridge, foodContents=[]),
FoodStorage(name=cabinet, foodContents=[
Food(name=rice, expired=false, storedIn=cabinet),
Food(name=flour, expired=false, storedIn=cabinet)
])
]
我尝试使用此代码:
String sql = """
select food_storage.*, food.* from food_storage
left outer join food on food.stored_in = food_storage.name and not food.expired;
""";
Query query = entityManager.createNativeQuery(sql, FoodStorage.class);
System.out.println(query.getResultList());
但这是我得到的结果:
[
FoodStorage(name=drawer, foodContents=[
Food(name=teabags, expired=false, storedIn=drawer),
Food(name=beans, expired=true, storedIn=drawer)
]),
FoodStorage(name=fridge, foodContents=[
Food(name=leftovers, expired=true, storedIn=fridge)
]),
FoodStorage(name=cabinet, foodContents=[
Food(name=rice, expired=false, storedIn=cabinet),
Food(name=flour, expired=false, storedIn=cabinet)
]),
FoodStorage(name=cabinet, foodContents=[
Food(name=rice, expired=false, storedIn=cabinet),
Food(name=flour, expired=false, storedIn=cabinet)
])
]
Hibernate 似乎忽略了我的手动连接,而是只为每个结果行构造一个 FoodStorage-instance,然后根据 FoodStorage 获取所有 Food。我该如何克服这个问题?
我找到了 Hibernate 的 @Where 注释。不幸的是,对于我的实际情况,连接过滤器是动态的,所以我不能使用它。
【问题讨论】:
-
你必须使用原生查询吗?
-
谢谢,这回答了我的问题!如果您将其表述为答案,我可以接受并奖励您