Критерий запроса с проекциями, не выбирающими коллекцию "один ко многим"

Итак, у меня есть 2 спальных режима, как показано ниже

class Owner{

Integer id;
String name;
Integer age;
String address;

/* 
  Many more fields here
*/

Set<Cat> cats;

}

class Cat{
Owner owner; //referenced from Owner.id
String color;
}

Я запрашиваю таблицу владельца, используя следующие критерии:

Criteria criteria = session.createCriteria(Owner.class);
criteria.createAlias("cats", "cats");

ProjectionList projList = Projections.projectionList();
projList.add(Projections.property("id"), "id");
projList.add(Projections.property("name"), "name");
projList.add(Projections.property("cats"), "cats");

criteria.setProjection(projList);
criteria.setResultTransformer(Transformers.aliasToBean(Owner.class));
List<Owner> owners = (List<Owner>)criteria.list();

Мне нужен список владельцев с соответствующими кошками.

Если я не добавляю прогнозы (что эквивалентно выбору *), я получаю популяции кошек для каждого владельца. Но select * будет очень дорогим, так как таблица владельца имеет более 60 столбцов с отношением внешнего ключа ко многим другим таблицам. Я хочу использовать проекции, чтобы выбрать только необходимые столбцы, чтобы запрос выполнялся быстрее. И если я добавлю прогнозы и / или псевдоним, я получу владельцев, но без кошек (кошки для каждого владельца равны нулю).

Я много искал решение этой проблемы, пробовал все способы создания псевдонимов и проекций в критериях, и я пробовал даже использовать собственные ResultTransformers. Кажется, ни один из них не работает, когда я использую проекции.

Кто-нибудь еще сталкивался с подобными проблемами? Есть идеи?

1 ответ

Вопрос не очень понятен. Вы говорите, что если вы не добавите прогнозы, вы получите кошек для каждого владельца. Но затем в список проекций вы добавляете кошек в качестве проецируемого поля, так что в основном вам нужны кошки в результате, верно? И если да, то единственная причина использования прогнозов - не указывать возраст и адрес Владельца?

В качестве предложения, пожалуйста, попробуйте подумать, какой SQL вы получите из запроса? Вы хотите что-то вроде этого:

select id, name from owner;

Или как то так:

select o.id, o.namer, c.color from owner o join cat c on o.id = c.owner_id; 

Я думаю, важно сначала понять, что вы хотите получить, а затем, как это сделать в Hibernate.

РЕДАКТИРОВАТЬ: Хорошо, я думаю, я понимаю, что вы хотите достичь сейчас. Но я не думаю, что вы сможете делать это так, как вы хотите - извлекать непосредственно сущность Владелец с кошками, также населенными. Это связано с тем, что по умолчанию при применении проекций результатом будет не список сущностей-владельцев, а список объектов [].

Например, предположим, что вам нужен идентификатор владельца, имя владельца и цвет кошки. Ваши прогнозы будут выглядеть так:

projList.add(Projections.property("id"), "id");
projList.add(Projections.property("name"), "name");
projList.add(Projections.property("cats.color"), "catsColor");

и сгенерированный sql будет похож на тот, что был приведен выше с cat join.

Затем вы можете применить преобразователь результата. Это методы из интерфейса:

public Object transformTuple(Object[] tuple, String[] aliases);
public List transformList(List collection);

Теперь первый будет вызываться для каждого объекта в списке результатов, если вы хотите вернуть сопоставление каждой строки с объектом, но при желании вы можете обработать весь список и объединить результаты. Возможно, вам это понравится, потому что, например, у вас будет OwnerDto, в котором есть список цветов cat или список catDtos, и вы можете преобразовать результат в эту древовидную структуру. Помните, что из-за объединения ваш результат будет выглядеть следующим образом (скажем, у вас есть 2 владельца, каждый с котом):

tuple: [1, 'Owner1', 'white'] - aliases ['id', 'name', 'catsColor']
tuple: [1, 'Owner1', 'black'] - aliases ['id', 'name', 'catsColor']
tuple: [2, 'Owner2', 'yellow'] - aliases ['id', 'name', 'catsColor']
.. etc

Вот почему вы хотели бы, чтобы преобразователь результатов комбинировал этот необработанный список с чем-то более подходящим.

Идея состоит в том, что прогнозы очень полезны для получения только тех данных, которые вам нужны, и для повышения производительности, но теперь вы должны теперь, чтобы возвращаемые результаты не были объектами - вы должны подготовить их и использовать так, как они есть. Гораздо больше смысла преобразовывать проецируемые данные в DTO и использовать их как таковые, потому что именно поэтому вы используете проекции в первую очередь - чтобы не извлекать целые объекты, верно?

Будем надеяться, что это решит проблему, если вам нужно больше советов по этому вопросу, пожалуйста, оставьте комментарий.

Другие вопросы по тегам