有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

运行时的java hibernate筛选器关系

我有以下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,但我不认为他们是为了这个。我认为它们更适用于全局过滤,而不是特定对象的特殊关系过滤

非常欢迎向文档、术语等提供指导。我对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()时,将延迟执行此查询。此查询从表成员中进行选择,并在项目成员上进行联接

我不想将其合并到一个查询中,并从表项目成员中进行选择,因为这将导致大量解析开销。我不想以笛卡尔积结束

这可能吗


共 (2) 个答案

  1. # 1 楼答案

    正如我在评论中提到的,我建议在hibernate中使用研究标准和/或hql文档。举个简单的例子,根据标准,您可以执行以下操作(我假设Spring的会话工厂,但api在其他地方是相同的):

    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();
    

    编辑:你想要的功能如下:

    @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?你需要一些额外的工作来让它懒散地工作

  2. # 2 楼答案

    新的JPA 2.1规定了在连接条件下使用的可能性:

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