【问题标题】:Hibernate: How to get a field from a join table using @SecondaryTable with predicateHibernate:如何使用带有谓词的@SecondaryTable 从连接表中获取字段
【发布时间】:2017-10-03 15:37:13
【问题描述】:

我有 3 张桌子,但我只对它感兴趣

  • 表 A
  • A_Cat 中的“金额”字段(这是“A”和“类别”之间的连接表),用于明确定义的 cat_Id 值。此谓词使关系成为 OneToOne 而不是 OneToMany。

这是简化的结构:

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
);

Java 代码:

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

这会在 Hibernate 中为所有可能的值生成“A”和“A_Category”之间的连接。

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

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

PS:如果我使用@Formula,我可以得到我想要的,但是如果我想要更多来自A_Category 的字段,那么生成的sql 的性能就不是那么好,并且想避免在我的POJO 中编写sql。

【问题讨论】:

  • 可以为A 实体分配多个类别(每次都有不同的数量)吗?如果是,我不知道 Hibernate 但在纯 JPA 中,你需要两个 @OneToMany 关系(A -> AxCategoryCategory -> AxCategory
  • @Al1 是的,A 实体可以分配给多个类别,但我只对 1 个类别感兴趣。其他的用于其他应用程序。
  • 如果我理解正确,A_Category 表将始终具有相同的cat_id 但不同的a_id 和不同的amount?当您说其他类别用于其他应用程序时,这意味着它们(特定的除外)永远不会链接到A entities
  • @Al1 A_Category 表是一个真正的 @ManyToMany 连接表。每个A 都有很多cat_id,但对于我的应用程序,我只对其中一个感兴趣
  • 我分享了一些观点。由于太长,我发布了一个答案,请随时发表评论以讨论它。主要思想是将技术逻辑保持在实体级别,并在 EJB 级别实现业务逻辑

标签: java hibernate jpa


【解决方案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
}

命名查询

那么处理您的问题的一种方法是使用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 列表,只需在 WHERE 子句中创建另一个带有附加参数的 NamedQuery


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

【讨论】:

  • +1 谢谢,我不知道 NamedQueries。我要调查他们。关于您的回答,我认为我不需要 Category 实体。我也不确定这是我希望得到的答案,但这也可能是由于我对这个主题缺乏了解。
  • 不客气。根据我对您问题的理解,Category 是一个 我不需要也不想实现它,但我必须 实体,所以迟早您可能会实现它。无论如何,如果您有任何问题,请随时发表评论
猜你喜欢
  • 2018-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-19
  • 1970-01-01
  • 2020-11-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多