2015-01-09 3 views
3

У меня есть эти объекты:Spring JPA запроса данных ведет себя неожиданно

public class Order_status_sas { 
    private Order_sas order; 
    private Date lastModified; 
    ... 
} 

public class Order_sas { 
    private long id; 
    ... 
} 

Мой CrudRepository:

public interface StatusesWareHouseRepository extends CrudRepository<Order_status_sas, Long> { 
    Order_status_sas findFirstByOrderIdOrderByLastModifiedDesc(long id); 
} 

Я ожидаю, что метод findFirstByOrderIdOrderByLastModifiedDesc будет возвращать первую строку из таблицы Order_status_sas, где order.id = <some_id> отсортированный по полю lastModified , но в журнале я вижу этот вопрос:

Hibernate: select ... 
     from order_status_sas a 
      left outer join orders_sas b 
      on a.order_id=b.id 
     where b.id=? 
     order by a.last_modified desc 

Этот запрос не возвращает мне одну строку, но возвращает список строк. Кажется, что Spring Data не смотрят на слово First в имени моего метода. Кроме того, я получаю Исключение:

org.springframework.dao.IncorrectResultSizeDataAccessException: 
result returns more than one elements; nested exception is javax.persistence.NonUniqueResultException: result returns more than one elements 

Пожалуйста, скажите мне, что я делаю неправильно и как я могу достичь своей цели?

EDITED: Я отредактировал мой StatusesWareHouseRepository с пользовательским запросом:

@Query("select s from Order_status_sas s where s.order.id = ?1 order by s.lastModified desc limit 1") 
Order_status_sas findFirstByOrderIdOrderByLastModifiedDesc(long id); 

но запрос, выполненный Hibernate, не изменились. Это выглядит следующим образом:

select ... 
from order_status_sas s 
where s.order_id=? 
order by s.last_modified desc 
+0

На самом деле, это выглядит точно так же, как Spring Data смотрит на слово 'first' в вашем имени метода, или вы Wouldn» t получить 'IncorrectResultSizeDataAccessException'.Если у вас нет возможности изменить модель домена, вам, скорее всего, придется использовать запрос «Критерии» или ручной запрос. – avgvstvs

ответ

0

Вы пробовали добавить @Query аннотацию (см here) на верхней части метода findFirstByOrderIdOrderByLastModifiedDesc(..), чтобы указать ожидаемое поведение вручную? A (не связанный) пример того, как это может работать:

public interface InvoiceRepository extends JpaRepository<Invoice, Long> { 

    @Query("SELECT I FROM Invoice I JOIN I.customer C JOIN C.user U WHERE 
     U.username = :username") 
    public List<Invoice> findInvoicesByUsername(@Param("username") 
     String username); 
} 

Обратите внимание, что язык запросов, используемый в теле аннотаций, на самом деле JPQL, не SQL. Дополнительные примеры в аннотации @Query см. В документах Spring Data here.

PS: Я также имеющий противоречивые чувства по поводу вашей структуры объекта домена, т.е. действительно ли должен храниться экземпляр Order_sas в экземпляре Order_status_sas - она ​​не должно быть наоборот? Обычно вы хотите сохранить ссылочные объекты в своем основном доменном объекте, а не наоборот. (Там есть небольшая вероятность того, что я просто не получить это право, хотя.)

EDIT: Я бы даже пойти так далеко, чтобы сказать, что с учетом текущую модель предметной области, Hibernate делает все правильно, за исключением пропуская ни LIMIT 1, чтобы ограничить ожидаемый набор результатов одной строкой. Однако сам запрос крайне неэффективен и может быть улучшен путем исправления вашей модели перекошенного домена.

+0

Если вы используете «@ Query», я добьюсь ожидаемого поведения, но я хотел использовать этот метод, потому что, согласно документации, я могу достичь этой цели. Я не согласен с вами в отношении моей объектной структуры. Это отношения OneToMany, в которых у одного ордера много Order_status'es. Я хотел знать, что я делаю неправильно, что мой метод не вел себя так, как указано в документации. – polis

+0

IMO это неправильно, потому что вы предоставили ему нестандартную модель домена. Разумеется, 'Order_status' также может быть подключен к нескольким' Order'? Таким образом, вы больше не имеете отношения «один ко многим», а отношения «многие ко многим». Стандартная процедура обработки отношений «многие ко многим», как я уверен, вы знаете, посредством создания [таблиц соединения] (http://en.wikipedia.org/wiki/Junction_table). Таким образом, «стандартная» модель домена будет состоять из следующего: «Order_sas», «Order_status_link_sas» (таблица соединений), «Order_status_sas». –

+0

Обратите внимание, что 'Order_status_link_sas' не является * идеальным * именем для таблицы соединений, а скорее является примером. С некоторыми догадками вы, вероятно, могли бы получить лучшее, более значимое имя для него. –

2

Хорошо, я понял @PriduNeemre point. Давайте оставим модель БД и вернемся к вопросу JPA. Вот еще один пример:

@Entity 
public class Client { 
    .... 
} 

public interface ClientRepository extends CrudRepository<Client, Integer> { 

Client findFirstByOrderByNameDesc(); 
} 

Hibernate запрос по-прежнему выглядит следующим образом:

select ... 
from clients c 
order by c.name desc 
+0

Как я сказал ранее, единственное, чего не хватает в этом (и предыдущем) запросе, - это предложение SQL 'LIMIT 1'. Что касается того, как или если это может быть достигнуто - мы надеемся, что кто-то с более обширными знаниями о новых функциях Spring придет и поможет. Тем временем вы могли бы использовать некоторые из решений и обходных решений, упомянутых ранее. –

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