【问题标题】:JPA Native Query to map One to ManyJPA Native Query 映射一对多
【发布时间】:2020-01-06 16:11:02
【问题描述】:

我有一个复杂的 Oracle 查询,为了简单起见,它看起来像这样;

SQL> SELECT d.id AS dept_id,
  2    d.name AS dept_name,
  3    e.id AS emp_id,
  4    e.name AS emp_name,
  5    e.dept_id AS emp_dept_id
  6  FROM drs2_dept d, drs2_emp e
  7  WHERE d.id = e.dept_id (+)
  8  /

   DEPT_ID DEPT_NAME           EMP_ID      EMP_NAME      EMP_DEPT_ID
---------- ------------------- ---------- -------------- -----------
         1 SALES                       101 JOHN                    1
         1 SALES                       102 JANE                    1
         2 ADMIN                                                       

我的Department 班级是;

@SqlResultSetMapping(
    name = "Department.employeeMapping",
    classes = {
        @ConstructorResult(
            targetClass = Department.class,
            columns = {
                @ColumnResult(name = "DEPT_ID", type = Integer.class),
                @ColumnResult(name = "DEPT_NAME")
            }
        ),
        @ConstructorResult(
            targetClass = Employee.class,
            columns = {
                @ColumnResult(name = "EMP_ID", type = Integer.class),
                @ColumnResult(name = "EMP_NAME"),
                @ColumnResult(name = "EMP_DEPT_ID", type = Integer.class)
            }
        )
    }
)

@NamedNativeQuery(
    name = "Department.findAllEmployees",
    query = "SELECT d.id AS dept_id, " + 
            "  d.name AS dept_name,  " +
            "  e.id AS emp_id,  " +
            "  e.name AS emp_name " +
            "  e.dept_id AS emp_dept_id, " +
            "FROM drs2_dept d, drs2_emp e " +
            "WHERE d.id = e.dept_id (+)",
    resultSetMapping = "Department.employeeMapping"
)

@Entity
public class Department {
    @Id // JPA will not start without it.
    Integer id;  
    String name;

    @OneToMany // JPA will not start without it.
    List<Employee> employees = new ArrayList<>();

    public Department(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Department() {}

    // getters and setters
}

我的Employee 班级是;

@Entity
public class Employee {
    @Id Integer id;
    Integer departmentId;
    String name;

    public Employee(Integer id, String name, Integer departmentId) {
        this.id = id;
        this.name = name;
        this.departmentId = departmentId;
    }

    public Employee() {}

    // getters and setters
}

因为我使用的是@ConstructorResult,所以我可以得到数据,但它仍然是一个扁平结构,也就是说一个List&lt;Object[]&gt;有三个条目,每个条目都包含[Department, Employee]。所以我必须执行以下操作才能将Employee 记录移动到各自的Department 中;

@Component
public class DepartmentDAO  {

    @PersistenceContext EntityManager entityManager;

    public Collection<Department> getAllDepartments() {
        Query query = entityManager.createNamedQuery("Department.findAllEmployees");

        Map<Integer, Department> map = new HashMap<>();
        List<Object[]> list = query.getResultList();
        for (Object[] tuple: list) {
            Department d = (Department) tuple[0];
            if (! map.containsKey(d.getId())) {
                map.put(d.getId(), d);
            }
            d = map.get(d.getId());
            Employee e = (Employee) tuple[1];
            if (e.getId() != null) {
                d.getEmployees().add(e);
            }
        }
        return map.values();
    }
}

每当我向@OneToMany 添加任何其他属性时,我似乎都会在 Hibernate 日志中生成不正确的虚假 SQL(即不存在的列或表名),但正如我在此问题开头所述,我只想要本机 SQL - 我不希望 Hibernate 弄清楚我想要做什么。

有没有办法让 JPA/Hibernate 将 Employee 对象放入 Department 的列表中?

( 作为子注释,我在这里看到过这个问题,但在 2011 年之前从未回答或回答过,那时 JPA 和 Hibernate 可能已经取得了进展。

我还应该补充一点,在我的项目的其他地方,我已经将 DepartmentEmployee 完全映射为 CrudRepository@Table@Column 一起使用,但是他们的 @OneToMany 定义并不能描述我的身份在上面的查询中做,因此在我的示例代码中没有它们。 )

【问题讨论】:

  • 您能找到任何解决方案吗?我正在寻找相同的解决方案。
  • @user2723039 我没有找到解决方案。我使用的是 Spring,所以最终使用了 RowMapper。因此我失去了对“@Table”和“@Column”的好处

标签: jpa spring-data-jpa jpa-2.0 jpa-2.1


【解决方案1】:

此查询没有任何子句强制它使用本机实现。 事实上,这被认为是一种不好的做法。

试试这个:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Departament> cq = cb.createQuery(Departament.class);

Root<Departament> rootDepartament = cq.from(Departament.class);
Join<Departament,Employee> joinEmployee = rootDepartament.join(Departament_.employees,JoinType.Left);

cq.select(rootDepartament);

List<Departament> result = entityManager.createQuery(cq).getResultList();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-08
    • 2016-02-15
    • 2014-01-22
    • 1970-01-01
    相关资源
    最近更新 更多