2015-05-04 5 views
1

КонтекстРегистрация декартово произведение

Я посылаю некоторые файлы на некоторых предприятиях каждую неделю. Мне нужно каждую неделю и каждое предприятие резервировать, отправлен ли файл или нет.

Столы

  • лор (предприятие)
  • WEK (неделя)
  • фил (файл: ссылки Wek и ЛОР)

Решение с чистым SQL

Сделайте карточку ian продукт между ent и wek затем левое внешнее соединение fil. Это работает:

select * from 
    (
    select * from wek, ent e 
) as t1 
left join fil f 
    on f.ent_id = t1.ent_id 
    and f.wek_id = t1.wek_id 

Проблема:

Как перевести это в JPA (в CriteriaBuilder пути)?

Например, если я стараюсь:

CriteriaBuilder cb = em.getCriteriaBuilder(); 
CriteriaQuery<ResultClass> query = cb.createQuery(ResultClass.class); 
Root<Week> week = query.from(Week.class); 
Root<Enterprise> query.from(Enterprise.class); 
Expression<???> cartesianProduct = ??? //How? 
cartesianProduct.leftJoin(???_.file); 
query.where(
    cb.equal(file.get(File_.wek_id), week.get(Week.week_id)); 
) 

Использование 2 «из» пунктов дает мне декартово произведение, но как я оставил присоединиться к этому результату?

Unstatisfaying решение:

Создать вид:

CREATE VIEW view_ent_wek AS 
    SELECT ent_id as ent_id, wek_id as wek_id, ent_id || '-' || ent_id as id 
    FROM ent, wek; 

сопоставляет его сущность:

@Entity 
@Table(name = "view_ent_wek") 
public class WeekEnterprise { 

    @Id 
    @Column(name = "id") 
    private String id; 

    @ManyToOne 
    @JoinColumn(name = "ent_id") 
    private Enterprise enterprise; 

    @ManyToOne 
    @JoinColumn(name = "wek_id") 
    private Week week; 

    [...] 

Тогда я могу использовать его в запросе:

Root<WeekEnterprise> weekEnterprise = query.from(WeekEnterprise.class); 
weekEnterprise.join(...) 

Мне не нравится это решение, потому что это заставляет меня создать представление, которое, очевидно, не нужно. Есть идеи?

+0

Попробуйте использовать [CriteriaQuery MultiSelect] (https://docs.oracle.com/javaee/6/api/javax/persistence/criteria/CriteriaQuery.html#multiselect (javax.persistence.criteria.Selection ...)). Проверьте [Критерии присоединения запросов] (http://www.objectdb.com/java/jpa/query/jpql/from) – OO7

+0

Не уверен, но вы можете попробовать это. Учитывая, что u hv 'Test2' является классом' JoinColumn' в классе 'Test1'. Попробуйте этот корень root = criteria.from (Test1.class); root.get ("test2Object"). Get ("test1FieldInTest2"); '. Я думаю, что это дает перекрестное соединение между 'Test1' и' Test2'. – OO7

+0

Что именно вы хотите вернуть из своего запроса JPA. Я имею в виду, вам нужны столбцы или сами Сущности? Например, вам нужны только идентификаторы 'ent' и' wek', за которыми следует (возможно, нулевой) объект 'fil'? Или вы хотите вернуть объекты 'ent',' wek' и (возможно, null) 'fil'? – DuncanKinnear

ответ

1

Я не вижу смысла делать SQL-запрос в стиле отчетности с JPA, не говоря уже о Query Query.

Конечно, JPA (и его реализации) поддерживают запросы к кортежу (в отличие от запросов сущностей, см. Также: Hibernate tuple criteria queries), но кортежи не являются тем, что подходит JPA. Представьте, что вы хотите изменить этот отчет и добавить дополнительные вычисления. Не было бы намного проще сделать это с SQL?

Использование JPA для сопоставления объектам Java и для моделирования транзакций все еще имеет смысл, и, следовательно, ваше представление SQL-представлений уже неплохое, или если вы предпочитаете не хранить SQL в представлении, используйте собственный API запросов JPA:

List<Object[]> list = em.createNativeQuery(sql).getResultList(); 

Или:

List<WeekEnterprise> list = em.createNativeQuery(sql, WeekEnterprise.class) 
           .getResultList(); 
+1

Это имеет смысл. Представление было бы естественным решением или просто сырым SQL. Уровень ORM в этом случае представляет собой просто неуклюжий перевод фактического кода, который подается на РСУБД. –

+0

Я думал, что это моя идея № 2 .... –

+0

@AndreiI: Это вполне возможно ... Что вы хотите сказать об этом? :-) –

1

У меня есть некоторые идеи:

  1. С 2 JPA запросов. Во-первых: возьмите декартово произведение wek и предприятий. Во-вторых: возьмите внутреннее соединение между wek, предприятиями и файлами. Использует карту (wek_id + ent_id => Tuple (Wek, Ent, File)), чтобы быстро определить, куда поместить файл.

  2. Напишите простые SQL-запросы и выполните их с помощью JPA API.

  3. (Не думал об этом) Создайте обратную ссылку от Wek и Ent в файл (lazy загружен), а затем вы сможете продолжить свою первую идею.

0

Не знаю много о JPA, но и о Postgres. И я бы предложил этот превосходный запрос:

SELECT * 
FROM wek CROSS JOIN ent 
LEFT JOIN fil USING (ent_id, wek_id); 

Вам не нужен подзапрос.
Единственное различие в результате (кроме того, чтобы быть короче и быстрее): вы получаете столбцы ent_id и wek_idодин раз на выходе (что может решить проблему с дублируемыми именами столбцов).

Должно быть легко перевести на JPA сейчас.

+0

Как это решение быстрее? –

+0

@LukasEder. Один подзапрос меньше (время строгания) и два меньше столбцов вывода (передача и обработка данных). Это не будет много, так что это просто в стороне от моего ответа. –

+0

ОК, я вижу ... Хм, кроме случайного конфликта с кешем, у меня еще не было проблем с временем планирования на этой шкале (в Oracle). Возможно, это зависит от механизма SQL. Что касается передачи данных - «SELECT *» - это злая часть, не обязательно «join condition» и «named columns join». Но здесь обсуждается академическое :) –

Смежные вопросы