Hibernate:如何使用@SecondaryTable和谓词从连接表中获取字段

时间:2017-10-03 15:37:13

标签: java hibernate jpa

我有3张桌子,但我只对

感兴趣
  • 表A
  • '金额'来自A_Cat的字段(这是" A"和"类别"之间的连接表),用于明确定义的cat_Id值。这个谓词使关系成为OneToOne而不是OneToMany。

这是简化的结构:

<?php

$line = "ESFEDTH_ZD0099";
if(preg_match("/(^[a-zA-Z0-9]*)_([a-zA-Z]{2})([0-9]{4})/", $line)) {
    echo "A match was found.";
} else {
    echo "A match was not found.";
}
?>

Java代码:

CREATE TABLE A
(
    a_id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(50) NOT NULL
);

CREATE TABLE Category
(
    cat_id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(50) NOT NULL
);

CREATE TABLE A_Category
(
    a_id INT PRIMARY KEY,
    cat_id INT PRIMARY KEY,
    amount INTEGER NOT NULL
);

这会在&#34; A&#34;之间生成Hibernate中的连接。和&#34; A_Category&#34;所有可能的值。

所以,这是我的问题,如何向SecondaryTable添加谓词(例如:cat_id = 1)。

可以使用注释完成吗?我用@WhereJoinTable尝试过但没有运气。

PS:如果我使用@Formula,我可以获得我想要的东西,但是如果我想要更多来自@Entity @Table(name = "A") @SecondaryTable(name = "A_Category", pkJoinColumns = {@PrimaryKeyJoinColumn(name = "a_id")})) public class ModelA { @Id @Column(name = "a_id") private Long id; @Column(name = "amount", table = "A_Category") private Integer amount; } 的字段,那么生成的sql不是那么高效,并且喜欢避免在我的POJO中编写sql。

1 个答案:

答案 0 :(得分:1)

JPA实体

JPA实体必须反映数据库结构,不应直接涉及业务逻辑。从您的简化结构,我假设您可以使用这些实体:

@Entity
@Table(name = "A")
public class A{

    @Id
    @Column(name = "a_id")
    private Long id;

    @Column(name = "title")
    private String title;

    @OneToMany(mappedBy = "a")
    private List<ACategory> categoryList;

    // no-arg constructor
    public A(){
        // initialise the list in the no-arg constructor to avoid bad surprises...
        this.categoryList = new ArrayList<>();
    }

    // getters & setters
}

作为ManyToMany关系has an extra column,您需要ACategory实体:

@Entity
@Table(name = "A_Category")
public class ACategory{

    // dedicated id column, see note(*) below
    @Id
    @Column(name = "id")
    private Long id;

    // foreign key to "A" table
    @ManyToOne
    @JoinColumn(name = "a_id")
    private A a;

    // foreign key to "Category" table
    @ManyToOne
    @JoinColumn(name = "cat_id")
    private Category category;

    @Column(name = "amount")
    private Integer amount;

    // no-arg constructor

    // getters & setters
}

(*):请注意ACategory有一个专用的id列。它会避免某些问题,例如this question

为了完整起见,Category实体看起来像

@Entity
@Table(name = "Category")
public class Category{

        @Id
        @Column(name = "cat_id")
        private Long id;

        @Column(name = "title")
        private String title;

        @OneToMany(mappedBy = "category")
        private List<ACategory> aList;

        // no-arg constructor
        public Category(){
            this.aList = new ArrayList<>();
        }

        // getters & setters
}

NamedQueries

然后,处理问题的方法是使用JPQL @NamedQuery,您可以在其中拥有业务逻辑。一个例子可能是:

@Entity
@Table(name = "A")
@NamedQuery(
    name="A.findAllByCategoryId"
    query="SELECT a FROM A a "
        + "INNER JOIN a.categoryList relACat "
        + "INNER JOIN relACate.category c"
        + "WHERE c.id = :categoryId"
)
public class A{
    // cf. above
}

我使用named parameters,但您也可以使用ordinal parameters

查询

然后,在与A实体关联的服务中,您可以这样使用命名查询:

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;

@Stateless
public class AService{

    // @PersistenceContext properly filled
    private EntityManager em;

    public List<A> fetchAEntities(){
        TypedQuery<A> query = em.createNamedQuery("A.findAllByCategoryId", A.class);
        // it seems you can afford hardcoding it
        query.setParameter("categoryId", 1);

        return query.getResultLis();
    }
}

如果不是A列表,而是希望拥有特定的A实体,只需在NamedQuery子句中创建另一个带有附加参数的WHERE

作为非Hibernate用户,这是一个纯粹的JPA解决方案