2014-09-14 4 views
0

У меня есть следующие объекты POJO:спящий режим - фильтр отношение во время выполнения

@Entity(name = "member") 
@Table(name = "member") 
public class Member { 
    @Column(name = "identifier") 
    @Id 
    @GeneratedValue 
    private int mIdentifier; 

    @Column(name = "name", columnDefinition = "text") 
    private String mName; 

    @ManyToMany(mappedBy = "mMembers") 
    private Set<Project> mProjects = new HashSet<Project>(); 

    public int getIdentifier() { 
     return mIdentifier; 
    } 

    public String getName() { 
     return mName; 
    } 

    public void setName(final String pName) { 
     mName = pName; 
    } 

    public Set<Project> getProjects() { 
     return mProjects; 
    } 

    public Member() { 
    } 
} 

и

@Entity(name = "project") 
@Table(name = "project") 
public class Project { 
    @Column(name = "identifier") 
    @Id 
    @GeneratedValue 
    private int mIdentifier; 

    @ManyToMany(cascade = CascadeType.ALL) 
    private Set<Member> mMembers = new HashSet<Member>(); 

    public int getIdentifier() { 
     return mIdentifier; 
    } 

    public Set<Member> getMembers() { 
     return mMembers; 
    } 

    public Project() { 
    } 
} 

Следующий код выбирает определенный проект, и возвращает все элементы:

Project project = (Project) db.load(Project.class, 1); 

System.out.println(project); 
System.out.println(project.getMembers()); 

Как фильтровать участников проекта? Например, скажите, что мне нужны только члены, имя которых начинается с «a». Я мог бы сделать некоторую фильтрацию на стороне клиента (с Guava & Predicate, например), но имеет смысл позволить Hibernate изменять SQL-запрос.

Я знаю Hibernate filters, но я не думаю, что они предназначены для этого. Я думаю, что они более полезны для глобальной фильтрации, а не для фильтрации ad-hoc-отношений одного конкретного объекта.

Указатели на документацию, терминологию и т. Д. Очень приветствуются. Я довольно новичок в Hibernate, и мне сложно получить документацию по этому вопросу.

редактировать

Я попытался с критериями. У меня есть два члена: «Джон Сноу» и «Снег». Следующий элемент возвращает оба члена.

final Criteria criteria = db.createCriteria(Project.class) 
     .createCriteria("mMembers") 
     .add(Restrictions.eq("mName", "John Snow")); 

for (final Project project : (List<Project>) criteria.list()) { 
    System.out.println(project.getIdentifier()); 

    for (final Member member : project.getMembers()) { 
     System.out.println(member.getName()); 
    } 
} 

Есть идеи?

редактировать (2)

Это выглядит как второй запрос выполняется, для извлечения всех членов. Как мы можем предотвратить это и полагаться только на данные, основанные на критериях?

Hibernate: 
    select 
     this_.identifier as identifi1_1_1_, 
     mmembers3_.mProjects_identifier as mProject1_1_, 
     mmembers1_.identifier as mMembers2_2_, 
     mmembers1_.identifier as identifi1_0_0_, 
     mmembers1_.name as name2_0_0_ 
    from 
     project this_ 
    inner join 
     project_member mmembers3_ 
      on this_.identifier=mmembers3_.mProjects_identifier 
    inner join 
     member mmembers1_ 
      on mmembers3_.mMembers_identifier=mmembers1_.identifier 
    where 
     mmembers1_.name=? 
1 
Hibernate: 
    select 
     mmembers0_.mProjects_identifier as mProject1_1_1_, 
     mmembers0_.mMembers_identifier as mMembers2_2_1_, 
     member1_.identifier as identifi1_0_0_, 
     member1_.name as name2_0_0_ 
    from 
     project_member mmembers0_ 
    inner join 
     member member1_ 
      on mmembers0_.mMembers_identifier=member1_.identifier 
    where 
     mmembers0_.mProjects_identifier=? 
Snow 
John Snow 

редактировать (3)

Глядя на первый запрос выше, это на самом деле не хочу я хочу. В сущности, я хочу два запроса:

  1. Первые запросы выбирают определенный проект. Этот запрос выбирает из таблицы проект.
  2. Второй запрос извлекает все элементы, соответствующие определенным критериям. Этот запрос выполняется лениво, когда вызывается getMembers(). Этот запрос выбирает из таблицы участник и присоединяется к project_member.

Я не хочу, чтобы объединить это в один запрос и выбрать из таблицы project_member, так как это привело бы к большому разбору накладных расходов. Я не хочу в конечном итоге декартовой продукции.

Возможно ли это?

+0

Ну, как насчет критериев или hql? – kamil

+0

http://docs.jboss.org/hibernate/orm/4.3/manual/en-US/html_single/#querycriteria - Я изучу это! Благодаря! –

ответ

0

новый JPA 2.1 определяет возможность использования ON условия в соединениях:

select p from Project p left join p.members m ON m.name like 'a%' 
0

Как уже упоминался в моем комментарии, я предлагаю критерии исследования и/или HQL документацию в спящем режиме. Создание простого примера, с критериями, которые вы можете сделать следующее (я assumend Spring в сессионном заводе, но апите такое же в другом месте):

Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Project.class); 

List filteredProjects = criteria.createAlias("member", "member") //this will join members entity 
     .add(Restrictions.ilike("member.mName", "a", MatchMode.ANYWHERE)) //this will make like, with ignore case and at start and end 
     .list(); //and finally, list your entities 

Если вы хотите отличные результаты для проектов, это также легко, просто добавить еще один метод:

List filteredProjects = criteria.createAlias("member", "member") 
     .add(Restrictions.ilike("member.mName", "a", MatchMode.ANYWHERE)) 
     .setProjection(Projections.distinct(Projections.property("mIdentifier"))) //this will make distinct on your id property 
     .list(); 

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

List projects = session.createQuery("select distinct p from Project p join p.mMembers as m where m.mName like :param") 
     .setParameter("param", "%a%") 
     .list(); 

Edit: Ваше желаемое будет Функция добавления выглядеть примерно так:

@Entity(name = "project") 
@Table(name = "project") 
public class Project { 
    @Column(name = "identifier") 
    @Id 
    @GeneratedValue 
    private int mIdentifier; 

    @ManyToMany(cascade = CascadeType.ALL) 
    private Set<Member> mMembers = new HashSet<Member>(); 

    public int getIdentifier() { 
     return mIdentifier; 
    } 

    public Set<Member> getMembers() { 
     return mMembers; 
    } 

    public Project() { 
    } 

    @Formula("<YOUR SQL TO FILTER RESULT>") 
    @Basic(fetch=FetchType.LAZY) 
    public Set<Member> getFilteredMembers() { 
     return mMembers 
    } 
} 

Но в соответствии с этим: Is it possible to make @Formula annotation lazily loaded? вам необходима дополнительная работа, чтобы заставить его работать лениво.

+0

Спасибо за ваш ответ. См. Мое редактирование. Я попробовал что-то подобное с критериями (я не включил псевдоним), но безуспешно. Есть ли у вас какие-либо идеи? –

+0

Какой SQL сгенерирован с двойной createCriteria? Я не уверен, что это правильный способ присоединиться, попробуйте с псевдонимами вместо – kamil

+0

См. Edit (2)! Я также пробовал с псевдонимом, но второй запрос всегда случается. –

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