Используя JPA, как мне подключить поле объекта, если запрос более продвинут, чем таблица соединений?

Im, использующий Hibernate 4.1.3.Final с JPA 2.1 и MySQL 5.5.37. У меня есть объект со следующим полем:

@Entity
@Table(name = "category",
       uniqueConstraints = { @UniqueConstraint(columnNames = { "NAME" })}
)
public class Category implements Serializable, Comparable<Category> {
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "ID")
    @GeneratedValue(generator = "uuid-strategy")
    private String id;

    @NotEmpty
    private Set<Subject> subjects;

    ...
}

Нет простой таблицы соединений, чтобы связать поле subjects, вместо этого есть несколько более сложный запрос MySQL. Ниже приведен пример определения предметов, заданных определенным идентификатором категории:

SELECT DISTINCT e.subject_id 
FROM category c, resource_category rc, product_resource pr, 
     sb_product p, product_book pe, book e 
WHERE c.id = rc.category_id 
  AND rc.resource_id = pr.resource_id 
  AND pr.product_id = p.id 
  AND p.id = pe.product_id 
  AND pe.ebook_id = e.id 
  AND c.id = ‘ABCEEFGH‘;

Каков самый простой способ подключить вышеуказанное поле, используя запрос ниже при загрузке категорий?

Этот вопрос касается работы с Java для достижения этого, поэтому построение представления или выполнение какого-либо другого типа безумия MySQL не является вариантом, по крайней мере, как ответ на этот вопрос.

Edit:

Добавлена ​​запись в предложение (заменяя '= "ABCDEFG" ' на '= id'), но Hibernate генерирует этот недопустимый SQL, когда я выполняю запросы для элементов, привязанных к объекту Category. Здесь вызывается SQL Hibernate

SELECT categories0_.resource_id AS RESOURCE1_75_0_,
       categories0_.category_id AS CATEGORY2_76_0_,
       category1_.id            AS ID1_29_1_,
       category1_.NAME          AS name2_29_1_,SELECT DISTINCT e.subject_id
FROM            category c,
                resource_category rc,
                product_resource pr,
                product p,
                product_ebook pe,
                book e
WHERE           c.id = rc.category_id
AND             rc.resource_id = pr.resource_id
AND             pr.product_id = p.id
AND             p.id = pe.product_id
AND             pe.ebook_id = e.id
AND             c.id = category1_.id as formula1_1_,
                subject2_.id         AS id1_102_2_,
                subject2_.NAME       AS name2_102_2_
FROM            resource_category categories0_
INNER JOIN      category category1_
ON              categories0_.category_id=category1_.id
LEFT OUTER JOIN subject subject2_
ONSELECT DISTINCT e.subject_id
FROM            category c,
                resource_category rc,
                product_resource pr,
                product p,
                product_ebook pe,
                book e
WHERE           c.id = rc.category_id
AND             rc.resource_id = pr.resource_id
AND             pr.product_id = p.id
AND             p.id = pe.product_id
AND             pe.ebook_id = e.id
AND             c.id = category1_.id=subject2_.id
where           categories0_.resource_id=?

Обратите внимание на конец "субъект субъекта левого внешнего соединения2" над SELECT DISTINCT e.subject_id "и" AND c.id = category1_.id = subject2_.id ".

Изменить 2:

Вот объект, участвующий в вышеуказанном запросе

@Entity
@Table(name="resource")
public class Resource implements Serializable, Comparable<Resource>
{
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(generator = "uuid-strategy")
    private String id;

    …    
    @Column(name = "FILE_NAME")
    private String fileName;

    @Column(name = "URI")
    private String uri;

    …

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "resource_category", joinColumns = { @JoinColumn(name = "RESOURCE_ID") }, inverseJoinColumns = { @JoinColumn(name = "CATEGORY_ID") })
    private Set<Category> categories;

и вот сам запрос...

CriteriaBuilder builder = m_entityManager.getCriteriaBuilder();
CriteriaQuery<T> criteria = builder.createQuery(Resource.class);
Root<T> rootCriteria = criteria.from(Resource.class);
criteria.select(rootCriteria).where(builder.equal(rootCriteria.get("uri"),uri));
Resource ret = null;
try {
        final TypedQuery<T> typedQuery = m_entityManager.createQuery(criteria);
        ret = typedQuery.getSingleResult();
} catch (NoResultException e) {
        LOG.warn(e.getMessage());
}
return ret; 

Ответ 1

Вам нужно использовать Hibernate, специфичный JoinColumnOrFormula:

public class Category implements Serializable, Comparable<Category> {
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "ID")
    @GeneratedValue(generator = "uuid-strategy")
    private String id;

    @NotEmpty
    @ManyToOne
    @JoinColumnsOrFormulas({
        @JoinColumnOrFormula(
            formula = @JoinFormula(
                value = 
                    "SELECT DISTINCT e.subject_id " +
                    "FROM category c, resource_category rc, product_resource pr, " +
                    "     sb_product p, product_book pe, book e " +
                    "WHERE c.id = rc.category_id " +
                    "  AND rc.resource_id = pr.resource_id " +
                    "  AND pr.product_id = p.id " +
                    "  AND p.id = pe.product_id " +
                    "  AND pe.ebook_id = e.id " +
                    "  AND c.id = ‘ABCEEFGH‘", 
                referencedColumnName="id"
            )
        )
    })
    private Set<Subject> subjects;

    ...
}

Изменить

Вы можете включить этот запрос в хранимую процедуру:

CREATE FUNCTION join_book(text) RETURNS text
    AS  'SELECT DISTINCT e.subject_id ' +
        'FROM category c, resource_category rc, product_resource pr, ' +
        '     sb_product p, product_book pe, book e ' +
        'WHERE c.id = rc.category_id ' +
        '  AND rc.resource_id = pr.resource_id ' +
        '  AND pr.product_id = p.id ' +
        '  AND p.id = pe.product_id ' +
        '  AND pe.ebook_id = e.id ' +
        '  AND c.id = $1;'  
    LANGUAGE SQL
    IMMUTABLE
    RETURNS NULL ON NULL INPUT;

Затем ваше отображение будет выглядеть следующим образом:

public class Category implements Serializable, Comparable<Category> {
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "ID")
    @GeneratedValue(generator = "uuid-strategy")
    private String id;

    @NotEmpty
    @ManyToOne
    @JoinColumnsOrFormulas({
        @JoinColumnOrFormula(
            formula = @JoinFormula(
                value = 
                    "join_book(id)", 
                referencedColumnName="id"
            )
        )
    })
    private Set<Subject> subjects;

    ...
}

Ответ 2

Реализация перехватчика спящего режима с помощью SessionFactory может помочь. У меня нет рабочего примера со мной.