Java JPA 防止代理调用 db

标签 java spring hibernate jpa spring-boot

我有一个使用 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/

相关文章:

java - 你觉得有必要把id字段标记为insertable = false和updatable = false吗?

java - 尽管缺少依赖项,但继续 Maven 构建

java - 显示 CSV 文件中的前 10 个单词

java - 使用正则表达式 (Java) 从这些字符串中提取子字符串

java - Spring 事务管理的问题?

Spring 数据 jpa 继承-每个类的表不起作用

java - 丰富 Collection

java - 映射非规范化 hibernate

Java 双下划线符号是做什么用的?

java - 在 hibernate 中使用参数进行日期转换