【问题标题】:Hibernate @ManyToMany not uses joinTable and produces Cartesian instead of inner joinHibernate @ManyToMany 不使用 joinTable 并产生笛卡尔而不是内部连接
【发布时间】:2018-10-21 06:41:42
【问题描述】:

同事们,当关系@ManyToMany. 项目实体:

    @Entity
    @Table(name = "PROJECT")
    @NamedQueries( {
        @NamedQuery(name = "Projects.employeesByExternal", query = "SELECT P FROM Project P INNER JOIN Employee E ON E.external=:external" )
    } )
    public class Project extends AbstractIdentified
    {
        @Column(name = "NAME") private String name;
        @Column(name = "EXT") private Boolean external;

        @ManyToMany
        @JoinTable( name = "EMPLOYEE_PROJECTS",
        joinColumns = { @JoinColumn(name = "PROJECT_ID") },
        inverseJoinColumns = { @JoinColumn(name = "EMPLOYEE_ID") } )
        private Set<Employee> employees;
    ... 
    // getters/setters here
    }

员工实体:

    @Entity
    @Table(name = "EMPLOYEE")
    public class Employee extends AbstractIdentified
    {
        @ManyToMany(mappedBy = "employees")
        private Set<Project> projects;
        ....
        // other fields and getters/setters here
    }

应用程序启动时会运行 init.sql:

insert into employee (id,status,ext) values (1,'CORP',true);
insert into employee (id,status,ext) values (2,'CORP',false);
insert into employee (id,status,ext) values (3, 'EXT',true);
insert into project (id,name) values (1,'project1');
insert into project (id,name) values (2,'project2');
insert into project (id,name) values (3,'project3');
insert into employee_projects (employee_id, project_id) values (1,1);
insert into employee_projects (employee_id, project_id) values (2,2);
insert into employee_projects (employee_id, project_id) values (3,3);

在 DAO 中,我准备了 DAO 方法来选择员工(至少一个)具有 external=false 的项目:

public List<Project> getProjectsByExternal( boolean isExternal )
{
    TypedQuery<Project> typedQuery = entityManager.createNamedQuery( "Projects.employeesByExternal", Project.class );
    typedQuery.setParameter( "external", isExternal );
    return typedQuery.getResultList();
}

现在我调用如下方法:

List<Project> list = projectDao.getProjectsByExternal(false);

而且我希望只得到一个 Project#2{name='project2'},但结果是 3 个项目:

01:03:49 INFO  vez.Starter - Project#1{name='project1'}
01:03:49 INFO  vez.Starter - Project#2{name='project2'}
01:03:49 INFO  vez.Starter - Project#3{name='project3'}

当我检查 Hibernate 生成了什么 SQL(属性 hibernate.show_sql = true)时,我注意到 Hibernate 创建连接表“PROJECT”和“EMPLOYEE”而不使用中间表“EMPLOYEE_PROJECTS”(参见项目类中的注释 @JoinTable) .有SQL生成:

01:03:49 DEBUG org.hibernate.SQL - 
    select
        project0_.ID as ID1_3_,
        project0_.NAME as NAME2_3_ 
    from
        PROJECT project0_ 
    inner join
        EMPLOYEE employee1_ 
            on ( employee1_.EXT=?)

实际上,这意味着已为所有项目选择并乘以一名员工。 我很困惑,因为这是我所期望的笛卡尔而不是内部连接。请指教我做错了什么?如何使用 NativeQuery 仅选择一个/多个员工具有外部属性 value=false 的项目? pom.xml:

<spring.version>5.0.5.RELEASE</spring.version>
<hibername.version>5.3.0.CR2</hibername.version>

【问题讨论】:

    标签: java hibernate jpa many-to-many


    【解决方案1】:

    问题来自您的 JPQL 查询:

    SELECT P FROM Project P INNER JOIN Employee E ON E.external=:external
    

    你应该把它改成:

    SELECT P 
    FROM Project P 
    INNER JOIN P.employees E 
    Where E.external=:external
    

    【讨论】:

    • 谢谢。我相应地将 JPQL 查询更改为:SELECT P FROM Project P INNER JOIN Employee E WHERE E.external=:external。奇怪的是,Hibernate 再次生成错误的 sql 查询:15:24:24 DEBUG org.hibernate.SQL - select project0_.ID as ID1_3_, project0_.NAME as NAME2_3_ from PROJECT project0_ inner join EMPLOYEE employee1_ on where employee1_.EXT=?。因此出现 SQLGrammarException java.sql.SQLSyntaxErrorException: Syntax error: Encountered "where" at line 1, column 116。休眠错误?
    • 您的 JPQL 仍然与我写的不匹配。使用 p.employees 别名。
    猜你喜欢
    • 2015-11-18
    • 2023-01-03
    • 1970-01-01
    • 1970-01-01
    • 2011-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多