HHH-13096 - Document that composite identifier cannot use auto-generated properties
This commit is contained in:
parent
84bc30d34a
commit
f4e36a1bea
|
@ -99,7 +99,7 @@ The restriction that a composite identifier has to be represented by a "primary
|
|||
Hibernate does allow composite identifiers to be defined without a "primary key class", although that modeling technique is deprecated and therefore omitted from this discussion.
|
||||
====
|
||||
|
||||
The attributes making up the composition can be either basic, composite, ManyToOne.
|
||||
The attributes making up the composition can be either basic, composite, `@ManyToOne`.
|
||||
Note especially that collections and one-to-ones are never appropriate.
|
||||
|
||||
[[identifiers-composite-aggregated]]
|
||||
|
@ -208,6 +208,69 @@ include::{sourcedir}/IdManyToOneTest.java[tag=identifiers-composite-id-fetching-
|
|||
----
|
||||
====
|
||||
|
||||
[[identifiers-composite-generated]]
|
||||
==== Composite identifiers with generated properties
|
||||
|
||||
When using composite identifiers, the underlying identifier properties must be manually assigned by the user.
|
||||
|
||||
Automatically generated properties are not supported can be used to generate the value of an underlying property that makes the composite identifier.
|
||||
|
||||
Therefore, you cannot use any of the automatic property generator described by the <<chapters/domain/basic_types.adoc#mapping-generated, generated properties section>> like `@Generated`, `@CreationTimestamp` or `@ValueGenerationType` or database-generated values.
|
||||
|
||||
Nevertheless, you can still generate the identifier properties prior to constructing the composite identifier, as illustrated by the following examples.
|
||||
|
||||
Assuming we have the following `EventId` composite identifier and an `Event` entity which uses the aforementioned composite identifier.
|
||||
|
||||
[[identifiers-composite-generated-mapping-example]]
|
||||
.The Event entity and EventId composite identifier
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/composite/Event.java[tag=identifiers-composite-generated-mapping-example, indent=0]
|
||||
----
|
||||
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/composite/EventId.java[tag=identifiers-composite-generated-mapping-example, indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
[[identifiers-composite-generated-in-memory]]
|
||||
===== In-memory generated composite identifier properties
|
||||
|
||||
If you want to generate the composite identifier properties in-memory,
|
||||
you need to do that as follows:
|
||||
|
||||
[[identifiers-composite-generated-in-memory-example]]
|
||||
.In-memory generated composite identifier properties example
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/composite/EmbeddedIdInMemoryGeneratedValueTest.java[tag=identifiers-composite-generated-in-memory-example, indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
Notice that the `createdOn` property of the `EventId` composite identifier was generated by the data access code and assigned to the
|
||||
identifier prior to persisting the `Event` entity.
|
||||
|
||||
[[identifiers-composite-generated-database]]
|
||||
===== Database generated composite identifier properties
|
||||
|
||||
If you want to generate the composite identifier properties using a database function or stored procedure,
|
||||
you could to do it as illustrated by the following example.
|
||||
|
||||
[[identifiers-composite-generated-database-example]]
|
||||
.Database generated composite identifier properties example
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/composite/EmbeddedIdDatabaseGeneratedValueTest.java[tag=identifiers-composite-generated-database-example, indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
Notice that the `createdOn` property of the `EventId` composite identifier was generated by calling the `CURRENT_TIMESTAMP` database function,
|
||||
and we assigned it to the composite identifier prior to persisting the `Event` entity.
|
||||
|
||||
[[identifiers-generators]]
|
||||
==== Generated identifier values
|
||||
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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.identifier.composite;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.hibernate.testing.RequiresDialect;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
@RequiresDialect(H2Dialect.class)
|
||||
public class EmbeddedIdDatabaseGeneratedValueTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { Event.class };
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-13096")
|
||||
public void test() {
|
||||
final EventId eventId = doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
//tag::identifiers-composite-generated-database-example[]
|
||||
Timestamp currentTimestamp = (Timestamp) entityManager
|
||||
.createNativeQuery(
|
||||
"SELECT CURRENT_TIMESTAMP" )
|
||||
.getSingleResult();
|
||||
|
||||
EventId id = new EventId();
|
||||
id.setCategory( 1 );
|
||||
id.setCreatedOn( currentTimestamp );
|
||||
|
||||
Event event = new Event();
|
||||
event.setId( id );
|
||||
event.setKey( "Temperature" );
|
||||
event.setValue( "9" );
|
||||
|
||||
entityManager.persist( event );
|
||||
//end::identifiers-composite-generated-database-example[]
|
||||
return event.getId();
|
||||
} );
|
||||
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
|
||||
Event event = entityManager.find( Event.class, eventId );
|
||||
|
||||
assertEquals( "Temperature", event.getKey() );
|
||||
assertEquals( "9", event.getValue() );
|
||||
|
||||
return event.getId();
|
||||
} );
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* 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.identifier.composite;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class EmbeddedIdInMemoryGeneratedValueTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { Event.class };
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-13096")
|
||||
public void test() {
|
||||
final EventId eventId = doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
//tag::identifiers-composite-generated-in-memory-example[]
|
||||
EventId id = new EventId();
|
||||
id.setCategory( 1 );
|
||||
id.setCreatedOn( new Timestamp( System.currentTimeMillis() ) );
|
||||
|
||||
Event event = new Event();
|
||||
event.setId( id );
|
||||
event.setKey( "Temperature" );
|
||||
event.setValue( "9" );
|
||||
|
||||
entityManager.persist( event );
|
||||
//end::identifiers-composite-generated-in-memory-example[]
|
||||
return event.getId();
|
||||
} );
|
||||
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
|
||||
Event event = entityManager.find( Event.class, eventId );
|
||||
|
||||
assertEquals( "Temperature", event.getKey() );
|
||||
assertEquals( "9", event.getValue() );
|
||||
|
||||
return event.getId();
|
||||
} );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* 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.identifier.composite;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
//tag::identifiers-composite-generated-mapping-example[]
|
||||
@Entity
|
||||
class Event {
|
||||
|
||||
@Id
|
||||
private EventId id;
|
||||
|
||||
private String key;
|
||||
|
||||
private String value;
|
||||
|
||||
//Getters and setters are omitted for brevity
|
||||
//end::identifiers-composite-generated-mapping-example[]
|
||||
|
||||
public EventId getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(EventId id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
//tag::identifiers-composite-generated-mapping-example[]
|
||||
}
|
||||
//end::identifiers-composite-generated-mapping-example[]
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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.identifier.composite;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Objects;
|
||||
import javax.persistence.Embeddable;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
//tag::identifiers-composite-generated-mapping-example[]
|
||||
@Embeddable
|
||||
class EventId implements Serializable {
|
||||
|
||||
private Integer category;
|
||||
|
||||
private Timestamp createdOn;
|
||||
|
||||
//Getters and setters are omitted for brevity
|
||||
//end::identifiers-composite-generated-mapping-example[]
|
||||
|
||||
public Integer getCategory() {
|
||||
return category;
|
||||
}
|
||||
|
||||
public void setCategory(Integer category) {
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
public Timestamp getCreatedOn() {
|
||||
return createdOn;
|
||||
}
|
||||
|
||||
public void setCreatedOn(Timestamp createdOn) {
|
||||
this.createdOn = createdOn;
|
||||
}
|
||||
|
||||
//tag::identifiers-composite-generated-mapping-example[]
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if ( this == o ) {
|
||||
return true;
|
||||
}
|
||||
if ( o == null || getClass() != o.getClass() ) {
|
||||
return false;
|
||||
}
|
||||
EventId that = (EventId) o;
|
||||
return Objects.equals( category, that.category ) &&
|
||||
Objects.equals( createdOn, that.createdOn );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash( category, createdOn );
|
||||
}
|
||||
}
|
||||
//end::identifiers-composite-generated-mapping-example[]
|
||||
|
Loading…
Reference in New Issue