【问题标题】:Hibernate Child Entity Condition Fetches Incorrect ChildHibernate 子实体条件获取不正确的子实体
【发布时间】:2017-02-22 00:31:07
【问题描述】:

我有一个父实体(公司)和子实体(员工),它们通过 COMPANY_ID 以一对多关系连接。 Company 和 Employee 都有状态栏。

公司实体:

@OneToMany(cascade = CascadeType.ALL, mappedBy = "company")
private List<Employee> employees = new ArrayList<>();

@Column(name = "COMPANY_STATUS")
private String status;

员工实体

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "COMPANY_ID", nullable = false)
private Company company;

@Column(name = "EMPLOYEE_STATUS")
private String status;

现在我需要获取所有公司(状态为 HIGH_PROFIT 或 LOW_PROFIT)和员工(状态为 PERMANENT)。我写了一个查询如下。

查询

    Criteria criteria = getSession().createCriteria(Company.class);
    List<String> statusList = new ArrayList<>();
    statusList.add("HIGH_PROFIT");
    statusList.add("LOW_PROFIT");
    criteria.add(Restrictions.in("status", statusList)).createCriteria("employees").add(Restrictions.eq("status", "PERMANENT"));
    criteria.list();

在运行应用程序时,我得到了正确的公司记录,其中员工没有按 PERMANENT 状态过滤,它包含所有具有 CONTRACT 和 PERMANENT 状态的孩子。

在检查休眠日志时,我看到 2 个查询正在执行

1. select this_.id as id1_3_2_, this_.COMPANY_NAME as COMPANY_NAME2_3_2_, this_.COMPANY_STATUS as COMPANY_STATUS3_3_2_, employ1_.id as id1_5_0_, employ1_.EMPLOYEE_STATUS as EMPLOYEE_STA4_5_0_ from COMPANY this_ inner join EMPLOYEE employ1_ on this_.id=employ1_.COMPANY_ID where this_.COMPANY_STATUS in (?, ?) and employ1_.EMPLOYEE_STATUS_ID=?

2. select employ0_.COMPANY_ID as COMPANY_ID5_5_0_, employ0_.id as id1_5_0_, employ0_.EMPLOYEE_STATUS as EMPLOYEE_STA4_5_1_ from EMPLOYEE employ0_ where employ0_.COMPANY_ID=?

我尝试在公司实体的员工变量上使用 @Fetch(FetchMode.SELECT) @Fetch(FetchMode.JOIN)@Fetch(FetchMode.SUBSELECT)(如下面的代码),但没有任何效果。

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "company")
    @Fetch(FetchMode.SELECT)
    private List<Employee> employees = new ArrayList<>();

我也尝试过在子实体上使用别名并在子实体上使用条件。它也没有工作。

有人可以帮我过滤状态正确的孩子吗?

【问题讨论】:

  • 在试用别名时,您是否使用了类似于 this 的内容?
  • 是的,我做到了。它给了我所有的记录。

标签: hibernate join subquery children


【解决方案1】:

你得到了绝对正确的结果:

您的@OneToMany 映射根本不应该被过滤!

您的查询被转换为以下句子:获取所有状态为“HIGH_PROFIT”和“LOW_PROFIT”且其中至少一名员工状态为“PERMANENT”的 CompanyEntities

为了让您有类似描述的内容,您应该切换到服务级别(即List&lt;EmployeeEntity&gt; fetchEmployeeInPermanentState(CompanyEntity entity) { /* write your query on EmployeeEntity here */ }

或者您可以在 CompanyEntity 上定义类似这样的字段:

@Filter(condition = "status = 'PERMANENT'")
@OneToMany(cascade = CascadeType.ALL, mappedBy = "company")
private List<Employee> permanentEmployees = new ArrayList<>();

【讨论】:

  • 不确定我是否理解这一点。我不能在实体中硬编码过滤器,因为我需要为不同的条件使用相同的实体。不是吗?在应用程序的其他部分,我还需要获取 CONTRACT 员工。
  • 您可以多定义 3 个字段:所有员工、合同员工和永久员工。或者如果你在 JAVA8 中,你可以创建一个单行来获取特定类型的员工transient listEmployee(String type) { return employees.stream().filter(o -&gt; o.status.equals(type)).collect(Collectors.toList()); }
  • 这听起来效率不高。我在应用程序的其他地方有类似的代码,它工作得非常好。我在这里做错了,我找不到它是什么。
  • 可以通过HQL实现吗?还是原生查询?
  • 不。除非您在 onetomany 上指定了 flter,否则您的 onetomany 不会被过滤,因为通常您要求您的实体管理器拥有同一实体的多个实体,这些字段是根据查询填充的。这不是创建实体管理器的目的。想象一下情况:您有 2 个 Company 实例,其中包含所有员工,其次只有 LOW_PROFIT,值存储在同一字段中。 entitymanager 应该如何保持这种状态?它应该信任哪一个?如果它选择一个实例而不是另一个实例,那么左边的怎么办?
猜你喜欢
  • 2012-11-10
  • 2016-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-11
  • 2017-09-27
  • 1970-01-01
相关资源
最近更新 更多