<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Sealyu

    --- 博客已遷移至: http://www.sealyu.com/blog

      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      618 隨筆 :: 87 文章 :: 225 評論 :: 0 Trackbacks

    About a year and an half ago I wrote an entry about the problem that rises when mapping an entity with multiple bags using eager fetching. At the end of the entry I suggested three different solutions: (a) to use lazy fetching, (b) to use sets instead of bags, and (c) to use the @IndexColumn annotation. Few months later I elaborated on the usage of @IndexColumn, this time another way – using the @CollectionId annotation.

    Environment

    ·         Hibernate Entity Manager – 3.3.1.GA

    ·         Hibernate core – 3.2.5.GA

    ·         Hibernate annotations- 3.3.0.GA

    ·         Database – PostgreSQL 8.1

    First one, first…

    Just before we start a warning – the @CollectionId annotation is a Hibernate specific annotation – not a part of the specification. And it doesn't work on one-to-many associations (but it can be used in conjunction with one-to-many associations). After putting that behind of us lets see the problem.

     

    The Problem

    Assume the following entities relation, a parent entity has two collections of child entities. Both collections should be eagerly loaded.


    First try will be to just to map it as is (Child1 has a many-to-many association; Child2 has a one-to-many):

     
    @ManyToMany( fetch = FetchType.EAGER, cascade=CascadeType.ALL)
    @JoinTable(name = "PARENT_CHILD1", 
    joinColumns = @JoinColumn(name = "PARENT_ID", referencedColumnName = "ID"), 
    inverseJoinColumns = @JoinColumn(name = "CHILD1_ID", referencedColumnName = "ID"))
    List<Child1> child1s = new LinkedList<Child1>();
     
    @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    List<Child2> child2s = new LinkedList<Child2>();

    But when loading a persistence unit with the above configuration the "org.hibernate.HibernateException: cannot simultaneously fetch multiple bags" will be thrown.

    Using an idbag

    The reason is that when we add the @CollectionId to a List or a Collection its semantics changes from "just a bag" to "a bag with primary key" (a.k.a, idbag). It means that a surrogate key is assigned to each row on the collection

    When transforming the association to Child1 into an idbag (using the @CollectionId annotation) the problem is solved. The reason is that when we switch the association semantics from "a simple bag" to "a bag with primary key" (a.k.a, idbag) it means that a surrogate key is assigned to each row on the collection.

    @Entity
    public class Parent {
    ………
    @ManyToMany( fetch = FetchType.EAGER, cascade=CascadeType.ALL)
    @JoinTable(name = "PARENT_CHILD1", 
    joinColumns = @JoinColumn(name = "PARENT_ID", referencedColumnName = "ID"), 
    inverseJoinColumns = @JoinColumn(name = "CHILD1_ID", referencedColumnName = "ID"))
    @GenericGenerator(name="uuid-gen", strategy = "uuid")
    @CollectionId(columns = @Column(name = "COL_ID"), type = @Type(type = "string"), generator = "uuid-gen")List<Child1> child1s = new LinkedList<Child1>();
     
    @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    List<Child2> child2s = new LinkedList<Child2>();
    }

    The problem with bags is that when Hibernate eagerly loads multiple collections it issues an outer join select to the RDBMS which can cause multiple entries on some of the collections. But when using an idbag each row in the collections is uniquely identified by the surrogate key, therefore Hibernate can identify it within the collection, even if the SQL statement returns an entry more than once.

    Notice the usage of a generator assigned to the collection id, the generator is responsible for creating the surrogate keys of the collection rows. I decided to use the UUID strategy. You can, of course, use JPA standard generators (such as Sequence or Table generators). The @CollectionId references the COL_ID column on PARENT_CHILD1 table (the join table). The value of the collection id is invisible to the application (it is not being mapped to a property).

     

    So why not on one-to-many

    The Hibernate annotations documentation says that to announce idbag semantics you should assign the @CollectionId to a @ManyToMany, @CollectionOfElements, or @OneToMany (look at the table on this section), but the Hibernate core documentation it says "Hibernate provides a feature that allows you to map many to many associations and collections of values to a table with a surrogate key." (here). I've tried it and indeed when annotating a @OneToMany collection with the @CollectionId an exception with the message "one-to-many collections with identifiers are not supported " is thrown by Hibernate.

    Idbag - Not Just For Eager Fetching

    Don't forge that you can use idbag for reasons other than solving multiple eager associations. For example it can give a major performance boost over simple bags for mutative operations. If entries in a collection have surrogate keys Hibernate will be able to locate the matching rows in the database using these keys (each row in the association table becomes unique) – there is no need for the fetch -> delete-all -> insert-all cycle when updating the collection.



    Posted at 03:49PM Jan 18, 2008 by Eyal Lupu in Persistence  |  Comments[6]

    Comments:

    Actually a @OneToMany @JoinTable would work (as opposed to @OneToMany @JoinColumn)

    Posted by Emmanuel Bernard on January 21, 2008 at 09:33 PM GMT+02:00 #

    Thanks Emmanuel,

    Maybe it worth a comment in the documentation. I guess this is actually an Hibernate core's issue (not an Hibernate annotation one - is it?).

    Posted by Eyal Lupu on January 21, 2008 at 11:56 PM GMT+02:00 #

    So, if I have 2 parallel OneToMany collections it's not fixable with:

    @OneToMany @CollectionId
    List<Son> getSons() {...}

    @OneToMany @CollectionId
    List<Daughter> getDaughter() {...}

    But if they were ManyToMany collections it is fixable?

    Strange :) Any particular reason?

    Posted by Geoffrey De Smet on January 23, 2008 at 11:11 AM GMT+02:00 #

    Hi Geoffrey,
    Yes - you have understood it correctly.

    I guess the reason is that regular one-to-many associations have a foreign key on the child record and there is no place to store the collection id there.

    However, see Emmanuel comment above - you can solve it using a join table.

    Posted by Eyal Lupu on January 23, 2008 at 11:59 AM GMT+02:00 #

    Year the documentation should be clearer.

    Posted by Emmanuel Bernard on January 23, 2008 at 04:48 PM GMT+02:00 #

    There is fourth solution of this problem. Works for both @OneToMany and @ManyToMany:

    @OneToMany(mappedBy="account", cascade=CascadeType.ALL)
    @LazyCollection(LazyCollectionOption.FALSE)
    private List<Entry> entries;

    Annotation @LazyCollection(LazyCollectionOption.FALSE) makes that collecion is loaded like with FetchType.EAGER and you can use it on two and more collections.
    This solution is (in my opinion) better because it's simplier. :)

    Posted by Bartosz Jakubowski on October 22, 2008 at 01:26 PM GMT+02:00 #

    posted on 2009-08-27 16:56 seal 閱讀(563) 評論(0)  編輯  收藏 所屬分類: Hibernate
    主站蜘蛛池模板: 特黄aa级毛片免费视频播放| 亚洲av无码专区在线| 成人精品综合免费视频| 在线不卡免费视频| 亚洲人成色99999在线观看| 成人午夜性A级毛片免费| 午夜在线a亚洲v天堂网2019| 噼里啪啦电影在线观看免费高清| 亚洲明星合成图综合区在线| 国产卡二卡三卡四卡免费网址| 亚洲午夜久久久精品电影院| 最近高清国语中文在线观看免费| 亚洲精品无码你懂的| 国产免费观看黄AV片| 亚洲一区二区三区免费| 亚洲va无码专区国产乱码| 污污网站免费观看| 亚洲国产精品久久久久秋霞影院| 日本XXX黄区免费看| 亚洲AV无码片一区二区三区| 亚洲日本一区二区三区在线不卡| 中国一级特黄高清免费的大片中国一级黄色片| 国产午夜亚洲精品理论片不卡 | 中文字幕亚洲综合久久菠萝蜜| 国产精品小视频免费无限app| 亚洲va国产va天堂va久久| 中文字幕免费在线看线人| 亚洲AV日韩综合一区尤物| 亚洲精品人成无码中文毛片| 久久成人免费播放网站| 久久亚洲精品专区蓝色区| 亚洲成人一区二区| 99re6热视频精品免费观看| 亚洲成aⅴ人片久青草影院按摩 | 亚洲人成亚洲精品| 四虎www成人影院免费观看| igao激情在线视频免费| 亚洲视频一区二区三区| 日日AV拍夜夜添久久免费| 亚洲精品国产福利一二区| 无码av免费网站|