What is referencedColumnName used for in JPA?

前端 未结 5 567
不知归路
不知归路 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).

    0 讨论(0)
  • 2020-11-29 20:15

    "referencedColumnName" property is the name of the column in the table that you are making reference with the column you are anotating. Or in a short manner: it's the column referenced in the destination table. Imagine something like this: cars and persons. One person can have many cars but one car belongs only to one person (sorry, I don't like anyone else driving my car).

    Table Person
    name char(64) primary key
    age int

    Table Car
    car_registration char(32) primary key
    car_brand (char 64)
    car_model (char64)
    owner_name char(64) foreign key references Person(name)

    When you implement classes you will have something like

    class Person{
       ...
    }
    
    class Car{
        ...
        @ManyToOne
        @JoinColumn([column]name="owner_name", referencedColumnName="name")
        private Person owner;
    }
    

    EDIT: as @searchengine27 has commented, columnName does not exist as a field in persistence section of Java7 docs. I can't remember where I took this property from, but I remember using it, that's why I'm leaving it in my example.

    0 讨论(0)
  • 2020-11-29 20:25

    It is there to specify another column as the default id column of the other table, e.g. consider the following

    TableA
      id int identity
      tableb_key varchar
    
    
    TableB
      id int identity
      key varchar unique
    
    // in class for TableA
    @JoinColumn(name="tableb_key", referencedColumnName="key")
    
    0 讨论(0)
  • 2020-11-29 20:25

    For a JPA 2.x example usage for the general case of two tables, with a @OneToMany unidirectional join see https://en.wikibooks.org/wiki/Java_Persistence/OneToMany#Example_of_a_JPA_2.x_unidirectional_OneToMany_relationship_annotations

    Screenshot from this WikiBooks JPA article: Example of a JPA 2.x unidirectional OneToMany relationship database

    0 讨论(0)
  • 2020-11-29 20:33

    Quoting API on referencedColumnName:

    The name of the column referenced by this foreign key column.

    Default (only applies if single join column is being used): The same name as the primary key column of the referenced table.

    Q/A

    Where this would be used?

    When there is a composite PK in referenced table, then you need to specify column name you are referencing.

    0 讨论(0)
提交回复
热议问题