【问题标题】:Querying an entity with filters on a OneToMany attribute gives a weird result在 OneToMany 属性上使用过滤器查询实体会产生奇怪的结果
【发布时间】:2012-01-14 09:20:05
【问题描述】:

我使用 EclipseLink 9 个月,到目前为止没有问题。因为我有 需要查询具有 OneToMany 属性的实体,情况恰恰相反。 它给了我一个奇怪的结果。 我已将实体简化到最大,但问题仍然存在。

我将解释我的需求,这非常简单:我有两个实体: 与地址有双向关系的人。 人可能有多个地址,但一个地址属于一个并且 只有一个人。

在类中,它给出了:

@Entity
public class Person implements Serializable {

    @Id
    private Long id;

    @OneToMany(mappedBy = "person", fetch = FetchType.LAZY)
    private Set<Address> addresses;

    // Getter and setter
      ...
}


@Entity
public class Address implements Serializable {

    @Id
    private String idAddress;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "idPerson", referencedColumnName = "idPerson")
    private Person person;

    // Getter and setter
    ...
}

我想用他们的地址查询人员。所有这一切都有一些条件 关于人员和地址。 我的简化查询:

select pers FROM Person pers join pers.addresses address
                 where pers.matricule=:matricule                    
                 and address.date=:dateContract

当我执行它时,我检索到正确的人,但包含所有地址 与此人链接(使用外键)。甚至那些没有的地址 与 dateContract 条件匹配。

这似乎是与在 oneToMany 上使用过滤有关的问题 我的查询中的属性。如果我做了几个请求,问题就解决了,但是 由于我有几个这样的请求,它会导致性能下降。 我已经尝试使用 oneToMany 进行急切的初始化并使用 fetch-join 查询提示,但我得到了相同的结果。

感谢您阅读我:)

PS : 代码我是手动写的,有点错字也不是不可能

大卫

【问题讨论】:

    标签: java jpa eclipselink jpql


    【解决方案1】:

    您的查询仅返回人员。一旦你得到了这些人,你就调用了 getAddresses(),它会懒惰地加载这个人的地址——所有这些。简而言之,查询限制了返回的人员集,但由于它只返回人员,因此在访问地址集时使用另一个查询延迟加载地址。

    您想要做的是在一个查询中返回带有一些地址的人。为此,您需要使用 fetch 关键字:

    select distinct pers FROM Person pers 
    join fetch pers.addresses address
    where pers.matricule = :matricule                    
    and address.date = :dateContract
    

    不过要非常小心:此查询返回的人员实体视图不正确。您应该确保不要修改返回人员的地址集合(尽管由于地址关联由Address.person 关联映射并且没有级联,因此在这种特殊情况下您应该没有问题)。

    【讨论】:

    • 它就像我在 Hibernate 中所说的那样工作。那么我猜你应该选择地址和人员,并自己关联人员和地址:select a, p from Address a inner join Person p where ...
    • 您好,感谢您的回复。我已经尝试过join fetch,它给出了相同的结果。此外,JPA 规范不允许为获取连接指定别名。 Eclipselink 遵循此行为,因此您的请求将引发异常。但我同意你的观点,即查询必须一次性执行。不幸的是,尽管有我的加入获取提示,EclipseLink 还是将它一分为二......
    • EclipseLink 将支持 join fetch,但会获取 person 的所有地址,因为这是构建一个完整的 person 所必需的。构建一个不完整的 Person 的问题在于,如果它被缓存,那么其他查询或其他想要完整 Person 的用户将获得部分查询。最好同时选择人员和地址,“select p, a from Person p join p.addresses a where ...”
    • 这种解决方案:子句选择中的多个对象很麻烦,因为 EclipseLink 不允许对这种查询使用“Fetch Join”提示。结果:它执行与我在 select 子句中要检索的对象一样多的 sql 查询。由于这个原因,我很快放弃了这个解决方案。有没有使用 EclipseLink 完成这项工作的好方法?
    猜你喜欢
    • 1970-01-01
    • 2015-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-11
    • 2019-04-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多