【问题标题】:How to join a table with one column of a view in that table's entity class如何将表与该表的实体类中的一列视图连接起来
【发布时间】:2018-07-06 01:00:35
【问题描述】:

场景:

  • 我有一个包含以下字段的产品表:id、代码、描述、照片。
  • 我有一个来自其他模式的 product_stock 视图,其中包含以下字段:prod_code、stok_tot

Misson:我需要在Spring Boot 中做的是将产品的总库存加入其中。

规则:

  • 我不能在这个任务上使用@Query,我需要在产品 Entity Class 中加入他们,这样stock 就变成了某种瞬态 产品领域。
  • 我无法更改产品 ID 是 Long 并且 ProductStock 的 ID 是 String 的事实,但我可以使用产品的代码字段来代替,对吗? (怎么做?)

到目前为止...我尝试使用@OneToOne 和@JoinColumn 来完成这项工作,但我的REST 给我的股票字段为NULL

“Estoque.java”

@Entity
@Table(name = "VW_ESTOQUE", schema = "ASICAT")
public class Estoque {

    @Id
    @Column(name = "CD_BEM_SERVICO", unique = true, nullable = false)
    private String codigo;

    @Column(name = "ESTOQUE")
    private Long estoque;

    // getters and setters hidden by me
}

“Produto.java”

@Entity
@NamedEntityGraph(name = "Produto.detail", attributeNodes = @NamedAttributeNode("categorias"))
public class Produto implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE)
    private Long id;

    private String codigo;

    private String descricao;

    // here is where I get the null values
    @Transient
    @OneToOne(fetch = FetchType.LAZY)
    @JoinTable(name = "VW_ESTOQUE", joinColumns = @JoinColumn(name = "CODIGO", referencedColumnName = "CODIGO"), inverseJoinColumns = @JoinColumn(name = "CD_BEM_SERVICO", referencedColumnName = "CODIGO"))
    private Estoque estoque;

    private String hash;

    @ManyToMany(mappedBy = "produtos", fetch = FetchType.EAGER)
    @BatchSize(size = 10)
    private List<Categoria> categorias = new ArrayList<>();

    // getters and setters hidden by me

}

在我的产品存储库中,我调用 FindAll()

【问题讨论】:

    标签: java oracle hibernate jpa spring-data


    【解决方案1】:

    您已将Produto.estoque 注释为@Transient,这意味着它不是实体持久状态的一部分。当该实体的实例被管理时,这样的字段既不会被写入也不会被读取。这不会达到你的目的。

    我可以想象您可能一直在努力实现两件事:

    1. 每次通过Produto 访问Estoque 时,都应从数据库中加载它以确保其新鲜度。 JPA 没有提供此功能,但您可能希望使用 @Cacheable(value = false) 注释 Estoque,并在关系的 Produto 一侧指定惰性获取策略。

    2. 您希望避免持久性提供程序尝试将任何更改持久化到 Estoque,因为它由视图支持,而不是可更新表。 这个我们可以解决。

    我的第一个建议是将ASICAT.VW_ESTOQUE 映射为辅助表,而不是完全独立的实体。这可能看起来像这样:

    @Entity
    @SecondaryTable(name = "VW_ESTOQUE", schema = "ASICAT"
            pkJoinColumns = {
                @PrimaryKeyJoinColumn(name = "CD_BEM_SERVICO",
                        referencedColumnName = "CODIGO") })
    public class Produto implements Serializable {
    
        @Id
        @GeneratedValue(strategy=GenerationType.SEQUENCE)
        private Long id;
    
        private String codigo;
    
        private String descricao;
    
        @Column(name = "ESTOQUE", table = "VW_ESTOQUE", nullable = true,
                insertable = false, updatable = false)
        private Long estoque;
    
        // ...
    }
    

    您还可以避免为estoque 属性提供setter。

    但是,如果您不能始终依赖ESTOQUE 视图为PRODUTO 的每一行提供一行,那么SecondaryTable 方法可能无法正常工作,因为检索中很可能会涉及内部连接。此外,您不会以这种方式获取惰性数据。主要替代方案或多或少是您在问题中提出的内容:设置一个单独的 Estoque 实体。

    如果您确实设置了一个单独的Estoque,那么我会以不同的方式处理它。具体来说,

    • 我会建立双向关系,这样我就可以
    • Estoque 实体设为关系所有者。

    这样的话:

    @Entity
    public class Produto implements Serializable {
    
        @Id
        @GeneratedValue(strategy=GenerationType.SEQUENCE)
        private Long id;
    
        private String codigo;
    
        private String descricao;
    
        // must not be @Transient:
        @OneToOne(fetch = FetchType.LAZY, mappedBy = "produto", cascade = {
                CascadeType.REFRESH
            })
        private Estoque estoque;
    
        // ...    
    }
    
    @Entity
    @Table(name = "VW_ESTOQUE", schema = "ASICAT")
    @Cacheable(value = false)
    public class Estoque {
    
        @Id
        @Column(name = "CD_BEM_SERVICO", nullable = false,
                insertable = false, updatable = false)
        private String codigo;
    
        @Column(name = "ESTOQUE", insertable = false, updatable = false)
        private Long estoque;
    
        @OneToOne(fetch = FetchType.LAZY, optional = false)
        @JoinColumn(name = "CD_BEM_SERVICO", referencedColumnName = "CODIGO",
            nullable = false, insertable = false, updatable = false, unique = true)
        Produto produto;
    
        // getters and setters hidden by me
    }
    

    在这种情况下,我会避免为Estoque 的任何属性提供setter 方法,并避免提供任何允许设置初始属性值的构造函数。因此,对于第一个近似值,唯一的 实例的属性将采用非空值的方式是它们是否由持久性提供程序设置。

    此外,由于您提到了 Oracle,如果您使用 TopLink 作为持久性提供程序,那么您可能会考虑将其 @ReadOnly 扩展属性应用于 Estoque 实体,以代替或什至作为其中一些保护措施的补充试图插入或更新视图。

    【讨论】:

    • 感谢您的帮助,我将在星期一测试这两种方法。我会使用那个有效的。反正我不需要 Estoque 成为一个实体,也不要懒惰。
    • 在你的第一个例子中:SecondaryTable JoinColumn cannot reference a non primary key
    猜你喜欢
    • 2011-02-05
    • 1970-01-01
    • 2016-07-16
    • 2015-06-04
    • 2019-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多