Skip to content

Commit

Permalink
HHH-11186 - Add examples for all Hibernate annotations
Browse files Browse the repository at this point in the history
Document more annotations:

- @JoinColumnOrFormula
  • Loading branch information
vladmihalcea committed Dec 2, 2016
1 parent c83efda commit 2f2debb
Show file tree
Hide file tree
Showing 5 changed files with 346 additions and 2 deletions.
Expand Up @@ -867,6 +867,8 @@ The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibern

The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/JoinColumnOrFormula.html[`@JoinColumnOrFormula`] annotation is used to specify that the entity association is resolved either through a FOREIGN KEY join (e.g. <<annotations-jpa-joincolumn>>) or using the result of a given SQL formula (e.g. <<annotations-hibernate-joinformula>>).

See the <<chapters/domain/basic_types.adoc#mapping-JoinColumnOrFormula,`@JoinColumnOrFormula` mapping>> section for more info.

[[annotations-hibernate-joincolumnsorformulas]]
==== `@JoinColumnsOrFormulas`

Expand All @@ -876,7 +878,7 @@ The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibern

The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/JoinFormula.html[`@JoinFormula`] annotation is used as a replacement for <<annotations-jpa-joincolumn>> when the association does not have a dedicated FOREIGN KEY column.

See the <<chapters/domain/basic_types.adoc#mapping-JoinFormula-example,`@JoinFormula` mapping>> section for more info.
See the <<chapters/domain/basic_types.adoc#mapping-JoinFormula,`@JoinFormula` mapping>> section for more info.

[[annotations-hibernate-lazycollection]]
==== `@LazyCollection`
Expand Down
Expand Up @@ -1880,4 +1880,54 @@ include::{extrasdir}/basic/mapping-JoinFormula-fetching-example.sql[]
----
====

Therefore, the `@JoinFormula` annotation is used to define a custom join association between the parent-child association.
Therefore, the `@JoinFormula` annotation is used to define a custom join association between the parent-child association.

[[mapping-JoinColumnOrFormula]]
==== `@JoinColumnOrFormula` mapping

The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/JoinColumnOrFormula.html[`@JoinColumnOrFormula`] annotation is used to customize the join between a child Foreign Key and a parent row Primary Key when we need to tak into consideration a column value as well as a `@JoinFormula`.

[[mapping-JoinColumnOrFormula-example]]
.`@JoinColumnOrFormula` mapping usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/JoinColumnOrFormulaTest.java[tags=mapping-JoinColumnOrFormula-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/mapping-JoinColumnOrFormula-example.sql[]
----
====

The `country` association in the `User` entity is mapped by the `language` property value and the the associated `Country` `is_default` column value.

Considering we have the following entities:

[[mapping-JoinColumnOrFormula-persistence-example]]
.`@JoinColumnOrFormula` mapping usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/JoinColumnOrFormulaTest.java[tags=mapping-JoinColumnOrFormula-persistence-example]
----
====

When fetching the `User` entities, the `country` property is mapped by the `@JoinColumnOrFormula` expression:

[[mapping-JoinColumnOrFormula-fetching-example]]
.`@JoinColumnOrFormula` mapping usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/JoinColumnOrFormulaTest.java[tags=mapping-JoinColumnOrFormula-fetching-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/mapping-JoinColumnOrFormula-fetching-example.sql[]
----
====

Therefore, the `@JoinColumnOrFormula` annotation is used to define a custom join association between the parent-child association.
@@ -0,0 +1,15 @@
CREATE TABLE countries (
id INTEGER NOT NULL,
is_default boolean,
name VARCHAR(255),
primaryLanguage VARCHAR(255),
PRIMARY KEY ( id )
)

CREATE TABLE users (
id BIGINT NOT NULL,
firstName VARCHAR(255),
language VARCHAR(255),
lastName VARCHAR(255),
PRIMARY KEY ( id )
)
@@ -0,0 +1,41 @@
SELECT
u.id as id1_1_0_,
u.language as language3_1_0_,
u.firstName as firstNam2_1_0_,
u.lastName as lastName4_1_0_,
1 as formula1_0_,
c.id as id1_0_1_,
c.is_default as is_defau2_0_1_,
c.name as name3_0_1_,
c.primaryLanguage as primaryL4_0_1_
FROM
users u
LEFT OUTER JOIN
countries c
ON u.language = c.primaryLanguage
AND 1 = c.is_default
WHERE
u.id = ?

-- binding parameter [1] as [BIGINT] - [1]

SELECT
u.id as id1_1_0_,
u.language as language3_1_0_,
u.firstName as firstNam2_1_0_,
u.lastName as lastName4_1_0_,
1 as formula1_0_,
c.id as id1_0_1_,
c.is_default as is_defau2_0_1_,
c.name as name3_0_1_,
c.primaryLanguage as primaryL4_0_1_
FROM
users u
LEFT OUTER JOIN
countries c
ON u.language = c.primaryLanguage
AND 1 = c.is_default
WHERE
u.id = ?

-- binding parameter [1] as [BIGINT] - [2]
@@ -0,0 +1,236 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.userguide.mapping.basic;

import java.io.Serializable;
import java.util.Objects;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import org.hibernate.annotations.JoinColumnOrFormula;
import org.hibernate.annotations.JoinFormula;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;

import org.junit.Test;

import org.jboss.logging.Logger;

import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.assertEquals;

/**
* @author Vlad Mihalcea
*/
public class JoinColumnOrFormulaTest extends BaseEntityManagerFunctionalTestCase {

private static final Logger log = Logger.getLogger( JoinColumnOrFormulaTest.class );

@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Country.class,
User.class
};
}

@Test
public void testLifecycle() {
//tag::mapping-JoinColumnOrFormula-persistence-example[]
Country US = new Country();
US.setId( 1 );
US.setDefault( true );
US.setPrimaryLanguage( "English" );
US.setName( "United States" );

Country Romania = new Country();
Romania.setId( 40 );
Romania.setDefault( true );
Romania.setName( "Romania" );
Romania.setPrimaryLanguage( "Romanian" );

doInJPA( this::entityManagerFactory, entityManager -> {
entityManager.persist( US );
entityManager.persist( Romania );
} );

doInJPA( this::entityManagerFactory, entityManager -> {
User user1 = new User( );
user1.setId( 1L );
user1.setFirstName( "John" );
user1.setLastName( "Doe" );
user1.setLanguage( "English" );
entityManager.persist( user1 );

User user2 = new User( );
user2.setId( 2L );
user2.setFirstName( "Vlad" );
user2.setLastName( "Mihalcea" );
user2.setLanguage( "Romanian" );
entityManager.persist( user2 );

} );
//end::mapping-JoinColumnOrFormula-persistence-example[]

//tag::mapping-JoinColumnOrFormula-fetching-example[]
doInJPA( this::entityManagerFactory, entityManager -> {
log.info( "Fetch User entities" );

User john = entityManager.find( User.class, 1L );
assertEquals( US, john.getCountry());

User vlad = entityManager.find( User.class, 2L );
assertEquals( Romania, vlad.getCountry());
} );
//end::mapping-JoinColumnOrFormula-fetching-example[]
}

//tag::mapping-JoinColumnOrFormula-example[]
@Entity(name = "User")
@Table(name = "users")
public static class User {

@Id
private Long id;

private String firstName;

private String lastName;

private String language;

@ManyToOne
@JoinColumnOrFormula( column =
@JoinColumn(
name = "language",
referencedColumnName = "primaryLanguage",
insertable = false,
updatable = false
)
)
@JoinColumnOrFormula( formula =
@JoinFormula(
value = "true",
referencedColumnName = "is_default"
)
)
private Country country;

//Getters and setters omitted for brevity

//end::mapping-JoinColumnOrFormula-example[]
public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public String getLanguage() {
return language;
}

public void setLanguage(String language) {
this.language = language;
}

public Country getCountry() {
return country;
}

public void setCountry(Country country) {
this.country = country;
}

//tag::mapping-JoinColumnOrFormula-example[]
}

@Entity(name = "Country")
@Table(name = "countries")
public static class Country implements Serializable {

@Id
private Integer id;

private String name;

private String primaryLanguage;

@Column(name = "is_default")
private boolean _default;

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getPrimaryLanguage() {
return primaryLanguage;
}

public void setPrimaryLanguage(String primaryLanguage) {
this.primaryLanguage = primaryLanguage;
}

public boolean isDefault() {
return _default;
}

public void setDefault(boolean _default) {
this._default = _default;
}

@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( !( o instanceof Country ) ) {
return false;
}
Country country = (Country) o;
return Objects.equals( getId(), country.getId() );
}

@Override
public int hashCode() {
return Objects.hash( getId() );
}
}
//end::mapping-JoinColumnOrFormula-example[]
}

0 comments on commit 2f2debb

Please sign in to comment.