Java 如何将表与该表中视图的一列联接';s实体类

Java 如何将表与该表中视图的一列联接';s实体类,java,oracle,hibernate,jpa,spring-data,Java,Oracle,Hibernate,Jpa,Spring Data,场景: 我有一个包含以下字段的products表:id、代码、描述、照片 我有一个来自其他模式的product_stock视图,其中包含字段:prod_code,stok_tot 米森:在Spring Boot中,我需要做的是将这些产品与它们的总库存结合起来 规则: 我不能在这个任务中使用@Query,我需要在产品实体类中加入它们,这样库存就变成了某种产品的临时字段 我不能改变这样一个事实,即产品的ID是一个长的,ProductStock的ID是一个字符串,但我可以使用产品的代码字段,对吗

场景:

  • 我有一个包含以下字段的products表:id、代码、描述、照片
  • 我有一个来自其他模式的product_stock视图,其中包含字段:prod_code,stok_tot
米森:
Spring Boot
中,我需要做的是将这些产品与它们的总库存结合起来

规则:

  • 我不能在这个任务中使用
    @Query
    ,我需要在产品
    实体类
    中加入它们,这样
    库存
    就变成了某种产品的临时字段
  • 我不能改变这样一个事实,即产品的ID是一个
    长的
    ,ProductStock的ID是一个
    字符串
    ,但我可以使用产品的代码字段,对吗?(怎么做?)
到目前为止……我试图使用@OneToOne和@JoinColumn来完成这项工作,但我的
REST
将stock字段设置为
NULL

“Estoque.java”

“Produto.java”

@实体
@NamedEntityGraph(name=“Produto.detail”,attributeNodes=@NamedAttributeNode(“categorias”))
公共类Produto实现了可序列化{
@身份证
@GeneratedValue(策略=GenerationType.SEQUENCE)
私人长id;
私有字符串codigo;
私有字符串描述符;
//这里是我得到空值的地方
@短暂的
@OneToOne(fetch=FetchType.LAZY)
@JoinTable(name=“VW_ESTOQUE”、joinColumns=@JoinColumn(name=“CODIGO”、ReferenceColumnName=“CODIGO”)、inverseJoinColumns=@JoinColumn(name=“CD_BEM_SERVICO”、ReferenceColumnName=“CODIGO”))
私人爱沙尼亚语;
私有字符串散列;
@ManyToMany(mappedBy=“produtos”,fetch=FetchType.EAGER)
@批量大小(大小=10)
私有列表categorias=new ArrayList();
//被我藏起来的能手和二传手
}

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

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

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

  • 每次通过
    Produto
    访问
    Estoque
    时,都应从数据库加载,以确保其新鲜度。JPA没有提供这种功能,尽管您可能希望使用
    @Cacheable(value=false)
    注释
    Estoque
    ,并在关系的
    Produto
    端指定延迟获取策略

  • 您希望避免持久化提供程序试图持久化对
    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方法,并避免提供任何允许设置初始属性值的构造函数。因此,在一级近似下 实例属性采用非null值的方式是,如果它们是由持久性提供程序设置的


    此外,由于您提到了Oracle,如果您使用TopLink作为持久性提供程序,那么您可能会考虑将其<代码> @ RealOnt< /Cord>扩展属性应用到<代码> Estoque <代码>实体中,代替或甚至添加一些保护措施,以避免插入或更新视图。我将在周一测试这两种方法。我将使用有效的方法。无论如何,我不需要Estoque成为一个实体,更不用说懒惰了。在第一个示例中:SecondaryTable JoinColumn不能引用非主键

    @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;
    
        // ...
    }
    
    @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
    }