What is referencedColumnName used for in JPA?

前端 未结 5 617
不知归路
不知归路 2020-11-29 19:42

In JPA there is an attribute called referencedColumnName that can be set on @JoinColumn, @PrimaryKeyJoinColumn what is the idea behind this setting

5条回答
  •  谎友^
    谎友^ (楼主)
    2020-11-29 20:14

    • name attribute points to the column containing the asociation, i.e. column name of the foreign key
    • referencedColumnName attribute points to the related column in asociated/referenced entity, i.e. column name of the primary key

    You are not required to fill the referencedColumnName if the referenced entity has single column as PK, because there is no doubt what column it references (i.e. the Address single column ID).

    @ManyToOne
    @JoinColumn(name="ADDR_ID")
    public Address getAddress() { return address; }
    

    However if the referenced entity has PK that spans multiple columns the order in which you specify @JoinColumn annotations has significance. It might work without the referencedColumnName specified, but that is just by luck. So you should map it like this:

    @ManyToOne
    @JoinColumns({
        @JoinColumn(name="ADDR_ID", referencedColumnName="ID"),
        @JoinColumn(name="ADDR_ZIP", referencedColumnName="ZIP")
    })
    public Address getAddress() { return address; }
    

    or in case of ManyToMany:

    @ManyToMany
    @JoinTable(
        name="CUST_ADDR",
        joinColumns=
            @JoinColumn(name="CUST_ID"),
        inverseJoinColumns={
            @JoinColumn(name="ADDR_ID", referencedColumnName="ID"),
            @JoinColumn(name="ADDR_ZIP", referencedColumnName="ZIP")
        }
    )
    

    Real life example

    Two queries generated by Hibernate of the same join table mapping, both without referenced column specified. Only the order of @JoinColumn annotations were changed.

    /* load collection Client.emails */ 
    select 
    emails0_.id_client as id1_18_1_,
    emails0_.rev as rev18_1_,
    emails0_.id_email as id3_1_,
    email1_.id_email as id1_6_0_
    
    from client_email emails0_ 
    inner join email email1_ on emails0_.id_email=email1_.id_email 
    
    where emails0_.id_client='2' and 
    emails0_.rev='18'
    
    /* load collection Client.emails */ 
    select
    emails0_.rev as rev18_1_,
    emails0_.id_client as id2_18_1_,
    emails0_.id_email as id3_1_, 
    email1_.id_email as id1_6_0_
    
    from client_email emails0_ 
    inner join email email1_ on emails0_.id_email=email1_.id_email 
    
    where emails0_.rev='2' and 
    emails0_.id_client='18'
    

    We are querying a join table to get client's emails. The {2, 18} is composite ID of Client. The order of column names is determined by your order of @JoinColumn annotations. The order of both integers is always the same, probably sorted by hibernate and that's why proper alignment with join table columns is required and we can't or should rely on mapping order.

    The interesting thing is the order of the integers does not match the order in which they are mapped in the entity - in that case I would expect {18, 2}. So it seems the Hibernate is sorting the column names before it use them in query. If this is true and you would order your @JoinColumn in the same way you would not need referencedColumnName, but I say this only for illustration.

    Properly filled referencedColumnName attributes result in exactly same query without the ambiguity, in my case the second query (rev = 2, id_client = 18).

提交回复
热议问题