所以我有一个对象Product,比如说,具有私有字符串名称和私有起源。代码如下:
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@Data
@NoArgsConstructor
@RequiredArgsConstructor
@AllArgsConstructor
public abstract class Product {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@NonNull
private String name;
@NonNull
@OneToOne(cascade = CascadeType.ALL)
private Origin origin;
}
现在我使用数据加载器在启动时将一些产品添加到数据库中,如下所示:
(Wine扩展了产品并增加了一些字符串(
repository.save(new Wine(
"Test wine"
new Origin(
"Crete",
"Greece"
)
));
此外,我有一个搜索端点,可以在其中搜索名称或原点。
public Page<Wine> searchProducts(
@RequestParam(name = "text", required = false) String searchTerm,
@RequestParam(required = false) Origin origin) {
return wineService.searchWines(
searchTerm,
origin
);
}
在葡萄酒服务中,我使用规范创建了一个查询。把它们都放在这里太夸张了,所以看看这个:
public static Specification<Wine> hasOrigin(Origin origin) {
return (root, criteriaQuery, criteriaBuilder) -> criteriaBuilder.equal(root.get(Wine_.ORIGIN), origin);
}
奇怪的是,它在一段时间前似乎有效,但现在不行了。现在,如果我搜索一款有特定产地的葡萄酒,它只会显示:
org.hibernate.TransientObjectException:对象引用未保存的瞬态实例-在刷新前保存瞬态实例:[created].backend.model.Origin
如何修复此问题?我看到了大约5个关于这个问题的不同帖子,他们都说";好吧,只需将级联ALL添加到Object";但我从一开始就这么做了。
编辑:来源实体代码:
@Entity
@Data
@NoArgsConstructor
@RequiredArgsConstructor
@AllArgsConstructor
@Table(name = "regions")
public class Origin {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@JsonIgnore
private long id;
@NonNull
private String region;
@NonNull
private String country;
}
首先连接Origin
,然后创建两个Predicate
,并将它们添加到生成器中并返回。
public static Specification<Wine> hasOrigin(Origin origin) {
return new Specification<Wine>() {
@Override
public Predicate toPredicate(Root<Wine> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
final List<Predicate> predicates = new ArrayList<>();
Join<Wine, Origin> originRoot = root.join("origin");
predicates.add(criteriaBuilder.equal(originRoot.get("country"), origin.getCountry()));
predicates.add(criteriaBuilder.equal(originRoot.get("region"), origin.getRegion()));
return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
}
};
}