代码之家  ›  专栏  ›  技术社区  ›  Rachel

Hibernate CollectionFeements急切获取重复元素

  •  37
  • Rachel  · 技术社区  · 17 年前

    我有一个名为SynonymMapping的类,它有一个映射为CollectionFements的值集合

    @Entity(name = "synonymmapping")
    public class SynonymMapping {
    
        @Id private String keyId;
    
        //@CollectionOfElements(fetch = FetchType.EAGER)
        @CollectionOfElements
        @JoinTable(name="synonymmappingvalues", joinColumns={@JoinColumn(name="keyId")})
        @Column(name="value", nullable=false)
        @Sort(type=SortType.NATURAL)
        private SortedSet<String> values;
    
        public SynonymMapping() {
            values = new TreeSet<String>();
        }
    
        public SynonymMapping(String key, SortedSet<String> values) {
            this();
            this.keyId = key;
            this.values = values;
        }
    
        public String getKeyId() {
            return keyId;
        }
    
        public Set<String> getValues() {
            return values;
        }
    }
    

    我有一个测试,我将两个同义词映射对象存储到数据库,然后要求数据库返回所有保存的同义词映射对象,期望接收我存储的两个对象。

    当我将值的映射更改为eager(如代码中注释掉的行所示)并再次运行测试时,我收到四个匹配项。

    我已经清除了运行之间的数据库,我可以复制这个问题,在渴望和懒惰之间交换。

    有人能告诉我为什么急切的抓取会复制这些对象吗?

    6 回复  |  直到 17 年前
        1
  •  75
  •   user176668 user176668    17 年前

    我也遇到了同样的问题-当您设置FetchType.EAGER以获得@collectionfements时,Hibernate会尝试一次性获取所有内容,即对链接到“master”对象的元素的每个条目使用一个查询。如果将@Fetch(FetchMode.SELECT)注释添加到集合中,则可以通过N+1次查询成功解决此问题。 在我的例子中,我希望有一个MediaObject实体及其元数据项(视频编解码器、音频编解码器、大小等)的集合。metadataItems集合的映射如下所示:

    @CollectionOfElements (targetElement = String.class, fetch = FetchType.EAGER)
    @JoinTable(name = "mo_metadata_item", joinColumns = @JoinColumn(name = "media_object_id"))
    @MapKey(columns = @Column(name = "name"))
    @Column (name = "value")
    @Fetch (FetchMode.SELECT)
    private Map<String, String> metadataItems = new HashMap<String, String>();
    
        2
  •  29
  •   ChssPly76    17 年前

    一般来说,在映射中强制执行即时抓取不是一个好主意-最好在适当的查询中指定即时连接(除非您100%确定在任何情况下,如果不填充集合,您的对象都没有意义/有效)。

    获取重复数据的原因是因为Hibernate在内部连接了根表和集合表。请注意,它们实际上是重复的,例如,对于2个同义词映射(每个映射有3个集合元素),您将得到6个结果(2x3),每个同义词映射实体的3个副本。因此,最简单的解决方法是将结果封装在一个集合中,从而确保它们是唯一的。

        3
  •  7
  •   Raja Anbazhagan    10 年前

    我曾经面对过这个问题,我用

    criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

    这将清除由于对子表进行联接而导致的重复项。

        4
  •  2
  •   Arthur Ronald    16 年前

    您可以使用SELECT DISTINCT(Hibernate查询语言)子句,如下所示

    SELECT DISTINCT synonym FROM SynonymMapping synonym LEFT JOIN FETCH synonym.values
    

    尽管组件和值类型集合的生命周期都绑定到所属实体类,但您应该在select子句中声明它们,以便检索它们。(左连接获取同义词.values)

    ChssPly76的答案是另一种方法,但不会忘记根据集合语义覆盖equals和hashcode方法

    当做

        5
  •  0
  •   Grigory Kislin    9 年前

    而不是 FetchMode.SELECT 对于N+1查询,最好使用 BatchSize e、 问题。 @BatchSize(size = 200) .

    DISTINCT 和 Criteria.DISTINCT_ROOT_ENTITY https://stackoverflow.com/a/46013654/548473

        6
  •  0
  •   Rahul Gangahar    8 年前

    我通过简单的添加实现了它

    session.createCriteria(ModelClass.class).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);