我有一个使用 Java 8 的 spring boot (1.5.4.RELEASE) 项目。我有一个实体,它的相关域类如下:
@Entity
@Table(name = "Foo", schema = "dbo")
public class FooEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "Id")
private int id;
@Column(name="Name")
private String name;
@Column(name="Type")
private String type;
@Column(name="Color")
private String color;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "Car")
private Car car;
//getter and setter
}
public class Foo {
private int id;
private String name;
private String type;
private String color;
private Car car;
//Constructors and getters
}
我想创建一个从数据库中获取此 Foo 对象的存储库,但仅在用户要求时获取复杂字段以防止不必要的连接语句。 repo 看起来像这样:
import static com.test.entities.QFooEntity.fooEntity;
import static com.test.entities.QCarEntity.carEntity;
@Repository
public class FooRepository {
private final JPAQuery<FooEntity> query = createQuery().from(fooEntity);
public FooRepository getFooByName(String name) {
query.where(fooEntity.name.eq(name));
return this;
}
public FooRepository withCar() {
query.leftJoin(fooEntity.car, carEntity).fetchJoin();
return this;
}
public Foo fetch() {
FooEntity entity = query.fetchOne();
return FooMapper.mapEntityToDomain().apply(entity);
}
}
因此,对 Foo 对象的准系统调用将返回具有除汽车字段之外的所有字段值的实体。如果用户想要汽车信息,那么他们必须显式调用 withCar
。
这是映射器:
public class FooMapper {
public static Function<FooEntity, Foo> mapEntityToDomain() {
return entity -> {
return new Foo(e.getId(), e.getName(), e.getType(), e.getColor(), e.getCar());
};
}
}
问题是,当您执行 e.getCar()
时,如果值不存在(即存在代理),JPA 会出去为您获取它。我不希望出现这种情况。它只会抓取值并将它们映射到等效域,如果它不存在则 null
。
我听说过(并尝试过)的一个解决方案是调用 em.detach(entity);
但是,这并没有按我的预期工作,因为当您尝试访问时它会引发异常getCar
我也听说这不是最佳实践。
所以我的问题是在 JPA 实体上使用构建器模式创建存储库的最佳方法是什么,并且在尝试映射时不让它调用数据库。
最佳答案
如果给定对象是代理且未初始化,您可以创建一个实用方法,该方法将返回 null
:
public static <T> T nullIfNotInitialized(T entity) {
return Hibernate.isInitialized(entity) ? entity : null;
}
然后你可以在需要的地方调用该方法:
return new Foo(e.getId(), e.getName(), e.getType(), e.getColor(), nullIfNotInitialized(e.getCar()));
关于Java JPA 防止代理调用 db,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46372656/