1

I have 3 tables, but I'm only interested in

  • table A
  • the 'amount' field from A_Cat (this is the join table between "A" and "Category") for a well defined value of cat_Id. This predicate makes the relation a OneToOne instead of a OneToMany.

This is the simplified structure:

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 code:

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

This generates a join in Hibernate between "A" and "A_Category" for all the possible values.

So, here's my question, how to add a predicate to the SecondaryTable (eg: cat_id = 1).

Can it be done with an annotation? I tried it with @WhereJoinTable but no luck.

PS: I can obtain what I want if I use @Formula, but if I want more fields from A_Category then the generated sql is not that performant and like to avoid writing sql in my POJO.

Al-un
  • 3,102
  • 2
  • 21
  • 40
Roeland Van Heddegem
  • 1,623
  • 2
  • 20
  • 35
  • Can a `A` entity be assigned multiple categories (each time with a different amount)? If yes, I don't know for Hibernate but in pure JPA, you'll need two `@OneToMany` relations (`A -> AxCategory` and `Category -> AxCategory`) – Al-un Oct 03 '17 at 17:18
  • @Al1 Yes, a `A` entity can be assigned to multiple categories, but I'm only interested in 1 categorie. The others are for other applications. – Roeland Van Heddegem Oct 04 '17 at 06:53
  • If I understand correctly, the `A_Category` table will always have the same `cat_id` but different `a_id` and different `amount`? When you said that other categories are for other applications, it means that they (except the specific one) will never be linked to `A entities`? – Al-un Oct 04 '17 at 07:19
  • @Al1 The `A_Category` table is a real `@ManyToMany` join table. Each `A` has many `cat_id`'s, but for my application I'm only interested in 1 of them – Roeland Van Heddegem Oct 04 '17 at 07:32
  • I shared some points. As it was too long, I posted an answer, feel free to comment on it to discuss about it. The main idea is to keep the technical logic at entities level and implement the business logic at the EJB level – Al-un Oct 04 '17 at 08:11

1 Answers1

1

JPA Entities

JPA entities must reflect the database structure and should not directly involve business logic. From your simplified structure, I assume you could use these entities:

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

As the ManyToMany relationship has an extra column, you'll need the ACategory entity:

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

(*): Notice that ACategory has a dedicated id column. It'll avoid some issue such as this question.

For completeness sake, the Category entity looks like

@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

Then a way to handle your issue is to use JPQL @NamedQuery where you can have business logic. An example could be:

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

I used named parameters but you can also use ordinal parameters.

Querying

Then, in your service associated to A entities, you can use the named query in this way:

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

If instead of a A list, you wish to have specific A entities, just create another NamedQuery with additional parameter in the WHERE clause.


As a non-Hibernate user, this is a pure JPA solution

Al-un
  • 3,102
  • 2
  • 21
  • 40
  • +1 Thx, I didn't knew NamedQueries. I'm going to investigate them. Regarding your answer, I don't think I need the `Category` entity. I'm also not sure this is the answer I was hoping for, but that could also be due to my lack of knowledge of this subject. – Roeland Van Heddegem Oct 04 '17 at 08:58
  • You're welcomed. From my understanding of your question, `Category` is an *I don't need and I don't want to implement it but I have to* entity so sooner or later you might implement it. Anyway, if you have any question, feel free to comment back – Al-un Oct 04 '17 at 09:00