Add Flushing chapter and JPQL section for batch updates
This commit is contained in:
parent
97ba351c2a
commit
90b7f9e07c
|
@ -10,6 +10,7 @@ include::chapters/architecture/Architecture.adoc[]
|
|||
include::chapters/domain/DomainModel.adoc[]
|
||||
include::chapters/bootstrap/Bootstrap.adoc[]
|
||||
include::chapters/pc/PersistenceContext.adoc[]
|
||||
include::chapters/flushing/Flushing.adoc[]
|
||||
include::chapters/jdbc/Database_Access.adoc[]
|
||||
include::chapters/transactions/Transactions.adoc[]
|
||||
include::chapters/jndi/JNDI.adoc[]
|
||||
|
|
|
@ -122,7 +122,9 @@ They have different semantics from the `save()`, `saveOrUpdate()`, and `delete()
|
|||
DML, or Data Manipulation Language, refers to SQL statements such as `INSERT`, `UPDATE`, and `DELETE`.
|
||||
Hibernate provides methods for bulk SQL-style DML statement execution, in the form of Hibernate Query Language (HQL).
|
||||
|
||||
==== HQL for UPDATE and DELETE
|
||||
==== HQL/JPQL for UPDATE and DELETE
|
||||
|
||||
Both the Hibernate native Query Language and JPQL (Java Persistence Query Language) provide support for bulk UPDATE and DELETE.
|
||||
|
||||
.Psuedo-syntax for UPDATE and DELETE statements using HQL
|
||||
====
|
||||
|
@ -146,15 +148,23 @@ If the entity name is not aliased, then it is illegal for any property reference
|
|||
Joins, either implicit or explicit, are prohibited in a bulk HQL query.
|
||||
You can use sub-queries in the `WHERE` clause, and the sub-queries themselves can contain joins.
|
||||
|
||||
.Executing an HQL UPDATE, using the `Query.executeUpdate()`
|
||||
.Executing a JPQL `UPDATE`, using the `Query.executeUpdate()`
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/executeUpdate.java[]
|
||||
include::{sourcedir}/jpql_update.java[]
|
||||
----
|
||||
====
|
||||
|
||||
In keeping with the EJB3 specification, HQL UPDATE statements, by default, do not effect the version or the timestamp property values for the affected entities.
|
||||
.Executing an HQL `UPDATE`, using the `Query.executeUpdate()`
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/hql_update.java[]
|
||||
----
|
||||
====
|
||||
|
||||
In keeping with the EJB3 specification, HQL `UPDATE` statements, by default, do not effect the version or the timestamp property values for the affected entities.
|
||||
You can use a versioned update to force Hibernate to reset the version or timestamp property values, by adding the `VERSIONED` keyword after the `UPDATE` keyword.
|
||||
|
||||
.Updating the version of timestamp
|
||||
|
@ -168,6 +178,16 @@ include::{sourcedir}/updating_version.java[]
|
|||
[NOTE]
|
||||
====
|
||||
If you use the `VERSIONED` statement, you cannot use custom version types, which use class `org.hibernate.usertype.UserVersionType`.
|
||||
|
||||
This feature is only available in HQL since it's not standardized by JPA.
|
||||
====
|
||||
|
||||
.A JPQL `DELETE` statement
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/jpql_delete.java[]
|
||||
----
|
||||
====
|
||||
|
||||
.An HQL `DELETE` statement
|
||||
|
@ -180,7 +200,7 @@ include::{sourcedir}/hql_delete.java[]
|
|||
|
||||
Method `Query.executeUpdate()` returns an `int` value, which indicates the number of entities effected by the operation.
|
||||
This may or may not correlate to the number of rows effected in the database.
|
||||
An HQL bulk operation might result in multiple SQL statements being executed, such as for joined-subclass.
|
||||
An JPQL/HQL bulk operation might result in multiple SQL statements being executed, such as for joined-subclass.
|
||||
In the example of joined-subclass, a `DELETE` against one of the subclasses may actually result in deletes in the tables underlying the join, or further down the inheritance hierarchy.
|
||||
|
||||
==== HQL syntax for INSERT
|
||||
|
@ -226,9 +246,4 @@ include::{sourcedir}/hql_insert.java[]
|
|||
----
|
||||
====
|
||||
|
||||
This section is only a brief overview of HQL. For more information, see <<chapters/query-hql/HQL.adoc#hql,HQL>>.
|
||||
|
||||
[[batch-bulk-jpql]]
|
||||
=== Java Persistence Query Language for DML
|
||||
|
||||
TODO
|
||||
This section is only a brief overview of HQL. For more information, see <<chapters/query-hql/HQL.adoc#hql,HQL>>.
|
|
@ -4,7 +4,8 @@ Transaction tx = session.beginTransaction();
|
|||
String hqlDelete = "delete Customer c where c.name = :oldName";
|
||||
// or String hqlDelete = "delete Customer where name = :oldName";
|
||||
int deletedEntities = session.createQuery( hqlDelete )
|
||||
.setString( "oldName", oldName )
|
||||
.executeUpdate();
|
||||
.setString( "oldName", oldName )
|
||||
.executeUpdate();
|
||||
|
||||
tx.commit();
|
||||
session.close();
|
||||
|
|
|
@ -3,6 +3,7 @@ Transaction tx = session.beginTransaction();
|
|||
|
||||
String hqlInsert = "insert into DelinquentAccount (id, name) select c.id, c.name from Customer c where ...";
|
||||
int createdEntities = session.createQuery( hqlInsert )
|
||||
.executeUpdate();
|
||||
.executeUpdate();
|
||||
|
||||
tx.commit();
|
||||
session.close();
|
||||
|
|
|
@ -4,8 +4,9 @@ Transaction tx = session.beginTransaction();
|
|||
String hqlUpdate = "update Customer c set c.name = :newName where c.name = :oldName";
|
||||
// or String hqlUpdate = "update Customer set name = :newName where name = :oldName";
|
||||
int updatedEntities = session.createQuery( hqlUpdate )
|
||||
.setString( "newName", newName )
|
||||
.setString( "oldName", oldName )
|
||||
.executeUpdate();
|
||||
.setString( "newName", newName )
|
||||
.setString( "oldName", oldName )
|
||||
.executeUpdate();
|
||||
|
||||
tx.commit();
|
||||
session.close();
|
|
@ -0,0 +1,11 @@
|
|||
EntityManager entityManager = entityManagerFactory.createEntityManager();
|
||||
EntityTransaction tx = entityManager.getTransaction();
|
||||
|
||||
String jpqlDelete = "delete Customer c where c.name = :oldName";
|
||||
// or String jpqlDelete = "delete Customer where name = :oldName";
|
||||
int updatedEntities = entityManager.createQuery( jpqlDelete )
|
||||
.setParameter( "oldName", oldName )
|
||||
.executeUpdate();
|
||||
|
||||
tx.commit();
|
||||
entityManager.close();
|
|
@ -0,0 +1,12 @@
|
|||
EntityManager entityManager = entityManagerFactory.createEntityManager();
|
||||
EntityTransaction tx = entityManager.getTransaction();
|
||||
|
||||
String jpqlUpdate = "update Customer c set c.name = :newName where c.name = :oldName";
|
||||
// or String query = "update Customer set name = :newName where name = :oldName";
|
||||
int updatedEntities = entityManager.createQuery( jpqlUpdate )
|
||||
.setParameter( "oldName", oldName )
|
||||
.setParameter( "newName", newName )
|
||||
.executeUpdate();
|
||||
|
||||
tx.commit();
|
||||
entityManager.close();
|
|
@ -524,8 +524,8 @@ Note that this can cause difficulty as the driver chooses to map many different
|
|||
|
||||
==== UUID as identifier
|
||||
|
||||
Hibernate supports using UUID values as identifiers, and they can even be generated on user'sbehalf.
|
||||
For details see the discussion of generators in <<chapters/domain/identifiers.adoc#identifiers,_Identifier generators_>>
|
||||
Hibernate supports using UUID values as identifiers, and they can even be generated on user's behalf.
|
||||
For details, see the discussion of generators in <<chapters/domain/identifiers.adoc#identifiers,_Identifier generators_>>.
|
||||
|
||||
[[basic-datetime]]
|
||||
==== Mapping Date/Time Values
|
||||
|
|
|
@ -1,12 +1,236 @@
|
|||
[[flushing]]
|
||||
== Flushing
|
||||
:sourcedir: ../../../../../test/java/org/hibernate/jpa/test/userguide/flush
|
||||
|
||||
* <<chapters/pc/PersistenceContext.adoc#pc,Persistence Contexts>>
|
||||
* <<chapters/query-hql/HQL.adoc#hql,HQL and JPQL>>
|
||||
* link:#criteria[???]
|
||||
* link:#querynative[???]
|
||||
Flushing is the process of synchronizing the state of the persistence context with the underlying database.
|
||||
The `EntityManager` and the Hibernate `Session` expose a set of methods, through which the application developer can change the persistent state of an entity.
|
||||
|
||||
Flushing is the process of synchronizing the state of the persistence
|
||||
context to the database.
|
||||
The persistence context acts as a transactional write-behind cache, queuing any entity state change.
|
||||
Like any write-behind cache, changes are first applied in-memory and synchronized with the database during flush time.
|
||||
The flush operation takes every entity state change and translates it to an `INSERT`, `UPDATE` or `DELETE` statement.
|
||||
|
||||
TODO
|
||||
[NOTE]
|
||||
====
|
||||
Because DML statements are grouped together, Hibernate can apply batching transparently.
|
||||
See the <<chapters/batch/Batching.adoc#batch,Batching chapter>> for more information.
|
||||
====
|
||||
|
||||
The flushing strategy is given by the http://docs.jboss.org/hibernate/stable/orm/javadocs/org/hibernate/Session.html#getFlushMode--[`flushMode`] of the current running Hibernate `Session`.
|
||||
Although JPA defines only two flushing strategies (https://docs.oracle.com/javaee/7/api/javax/persistence/FlushModeType.html#AUTO[`AUTO`] and https://docs.oracle.com/javaee/7/api/javax/persistence/FlushModeType.html#COMMIT[`COMMIT`]),
|
||||
Hibernate has a much broader spectrum of flush types:
|
||||
|
||||
ALWAYS:: Flushes the `Session` before every query.
|
||||
AUTO:: This is the default mode and it flushes the `Session` only if necessary.
|
||||
COMMIT:: The `Session` tries to delay the flush until the current `Transaction` is committed, although it might flush prematurely too.
|
||||
MANUAL:: The `Session` flushing is delegated to the application, which must call `Session.flush()` explicitly in order to apply the persistence context changes.
|
||||
|
||||
[[flushing-auto]]
|
||||
== `AUTO` flush
|
||||
|
||||
By default, Hibernate uses the `AUTO` flush mode which triggers a flush in the following circumstances:
|
||||
|
||||
* prior to committing a `Transaction`
|
||||
* prior to executing a JPQL/HQL query that overlaps with the queued entity actions
|
||||
* before executing any native SQL query that has no registered synchronization
|
||||
|
||||
=== `AUTO` flush on commit
|
||||
|
||||
In the following example, an entity is persisted and then the transaction is committed.
|
||||
|
||||
[[flushing-auto-flush-commit-example]]
|
||||
.Automatic flushing on commit
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/AutoFlushTest.java[tags=flushing-auto-flush-commit-example]
|
||||
----
|
||||
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{sourcedir}/flushing-auto-flush-commit-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
Hibernate logs the message prior to inserting the entity because the flush only occurred during transaction commit.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
This is valid for the `SEQUENCE` and `TABLE` identifier generators.
|
||||
The `IDENTITY` generator must execute the insert right after calling `persist()`.
|
||||
For details, see the discussion of generators in <<chapters/domain/identifiers.adoc#identifiers,_Identifier generators_>>.
|
||||
====
|
||||
|
||||
=== `AUTO` flush on JPQL/HQL query
|
||||
|
||||
A flush may also be triggered when executing an entity query.
|
||||
|
||||
[[flushing-auto-flush-jpql-example]]
|
||||
.Automatic flushing on JPQL/HQL
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/AutoFlushTest.java[tags=flushing-auto-flush-jpql-example]
|
||||
----
|
||||
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{sourcedir}/flushing-auto-flush-jpql-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
The reason why the `Advertisement` entity query didn't trigger a flush is because there's no overlapping between the `Advertisement` and the `Person` tables:
|
||||
|
||||
[[flushing-auto-flush-jpql-entity-example]]
|
||||
.Automatic flushing on JPQL/HQL entities
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/AutoFlushTest.java[tags=flushing-auto-flush-jpql-entity-example]
|
||||
----
|
||||
====
|
||||
|
||||
When querying for a `Person` entity, the flush is triggered prior to executing the entity query.
|
||||
|
||||
[[flushing-auto-flush-jpql-overlap-example]]
|
||||
.Automatic flushing on JPQL/HQL
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/AutoFlushTest.java[tags=flushing-auto-flush-jpql-overlap-example]
|
||||
----
|
||||
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{sourcedir}/flushing-auto-flush-jpql-overlap-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
This time, the flush was triggered by a JPQL query because the pending entity persist action overlaps with the query being executed.
|
||||
|
||||
=== `AUTO` flush on native SQL query
|
||||
|
||||
When executing a native SQL query, a flush is always triggered when using the `EntityManager` API.
|
||||
|
||||
[[flushing-auto-flush-sql-example]]
|
||||
.Automatic flushing on native SQL using `EntityManager`
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/AutoFlushTest.java[tags=flushing-auto-flush-sql-example]
|
||||
----
|
||||
====
|
||||
|
||||
The `Session` API doesn't trigger an `AUTO` flush when executing a native query
|
||||
|
||||
[[flushing-auto-flush-sql-native-example]]
|
||||
.Automatic flushing on native SQL using `Session`
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/AutoFlushTest.java[tags=flushing-auto-flush-sql-native-example]
|
||||
----
|
||||
====
|
||||
|
||||
To flush the `Session`, the query must use a synchronization:
|
||||
|
||||
[[flushing-auto-flush-sql-synchronization-example]]
|
||||
.Automatic flushing on native SQL with `Session` synchronization
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/AutoFlushTest.java[tags=flushing-auto-flush-sql-synchronization-example]
|
||||
----
|
||||
====
|
||||
|
||||
[[flushing-commit]]
|
||||
=== `COMMIT` flush
|
||||
|
||||
JPA also defines a COMMIT flush mode, which is described as follows:
|
||||
|
||||
[quote, Section 3.10.8 of the JPA 2.1 Specification]
|
||||
____
|
||||
If `FlushModeType.COMMIT` is set, the effect of updates made to entities in the persistence context upon queries is unspecified.
|
||||
____
|
||||
|
||||
When executing a JPQL query, the persistence context is only flushed when the current running transaction is committed.
|
||||
|
||||
[[flushing-commit-flush-jpql-example]]
|
||||
.`COMMIT` flushing on JPQL
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/CommitFlushTest.java[tags=flushing-commit-flush-jpql-example]
|
||||
----
|
||||
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{sourcedir}/flushing-commit-flush-jpql-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
Because the JPA doesn't impose a strict rule on delaying flushing, when executing a native SQL query, the persistence context is going to be flushed.
|
||||
|
||||
[[flushing-commit-flush-sql-example]]
|
||||
.`COMMIT` flushing on SQL
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/CommitFlushTest.java[tags=flushing-commit-flush-sql-example]
|
||||
----
|
||||
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{sourcedir}/flushing-commit-flush-sql-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
[[flushing-always]]
|
||||
=== `ALWAYS` flush
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
The `ALWAYS` is only available with the native `Session` API.
|
||||
====
|
||||
|
||||
The `ALWAYS` flush mode triggers a persistence context flush even when executing a native SQL query against the `Session` API.
|
||||
|
||||
[[flushing-always-flush-sql-example]]
|
||||
.`COMMIT` flushing on SQL
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/AlwaysFlushTest.java[tags=flushing-always-flush-sql-example]
|
||||
----
|
||||
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{sourcedir}/flushing-always-flush-sql-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
[[flushing-manual]]
|
||||
=== `MANUAL` flush
|
||||
|
||||
Both the `EntityManager` and the Hibernate `Session` define a `flush()` method that, when called, triggers a manual flush.
|
||||
Hibernate also defines a `MANUAL` flush mode, so the persistence context can only be flushed manually.
|
||||
|
||||
[[flushing-manual-flush-example]]
|
||||
.`MANUAL` flushing
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/ManualFlushTest.java[tags=flushing-manual-flush-example]
|
||||
----
|
||||
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{sourcedir}/flushing-manual-flush-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
The `INSERT` statement was not executed because the persistence context because there was no manual `flush()` call.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
This mode is useful when using multi-request logical transactions and only the last request should flush the persistence context.
|
||||
====
|
|
@ -25,6 +25,7 @@ import static org.hibernate.jpa.test.util.TransactionUtil.doInJPA;
|
|||
*/
|
||||
public class OneToManyUnidirectionalTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* 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.jpa.test.userguide.flush;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import static org.hibernate.jpa.test.util.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* <code>AlwaysFlushTest</code> - Always Flush Test
|
||||
*
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class AlwaysFlushTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
private static final Logger log = Logger.getLogger( AlwaysFlushTest.class);
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Person.class,
|
||||
Phone.class,
|
||||
Advertisement.class
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlushSQL() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
entityManager.createNativeQuery("delete from Person").executeUpdate();
|
||||
});
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
log.info("testFlushSQL");
|
||||
//tag::flushing-always-flush-sql-example[]
|
||||
Person person = new Person("John Doe");
|
||||
entityManager.persist(person);
|
||||
|
||||
Session session = entityManager.unwrap( Session.class);
|
||||
assertTrue(((Number) session
|
||||
.createSQLQuery("select count(*) from Person")
|
||||
.setFlushMode( FlushMode.ALWAYS)
|
||||
.uniqueResult()).intValue() == 1);
|
||||
//end::flushing-always-flush-sql-example[]
|
||||
});
|
||||
}
|
||||
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@OneToMany(mappedBy = "person", cascade = CascadeType.ALL)
|
||||
private List<Phone> phones = new ArrayList<>();
|
||||
|
||||
public Person() {
|
||||
}
|
||||
|
||||
public Person(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<Phone> getPhones() {
|
||||
return phones;
|
||||
}
|
||||
|
||||
public void addPhone(Phone phone) {
|
||||
phones.add(phone);
|
||||
phone.setPerson(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Phone")
|
||||
public static class Phone {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
@ManyToOne
|
||||
private Person person;
|
||||
|
||||
private String number;
|
||||
|
||||
public Phone() {
|
||||
}
|
||||
|
||||
public Phone(String number) {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public Person getPerson() {
|
||||
return person;
|
||||
}
|
||||
|
||||
public void setPerson(Person person) {
|
||||
this.person = person;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Advertisement")
|
||||
public static class Advertisement {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String title;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
* 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.jpa.test.userguide.flush;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityTransaction;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import static org.hibernate.jpa.test.util.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* <code>AlwaysFlushTest</code> - Always Flush Test
|
||||
*
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class AutoFlushTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
private static final Logger log = Logger.getLogger( AutoFlushTest.class );
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Person.class,
|
||||
Advertisement.class
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlushAutoCommit() {
|
||||
EntityManager entityManager = null;
|
||||
EntityTransaction txn = null;
|
||||
try {
|
||||
//tag::flushing-auto-flush-commit-example[]
|
||||
entityManager = entityManagerFactory().createEntityManager();
|
||||
txn = entityManager.getTransaction();
|
||||
txn.begin();
|
||||
|
||||
Person person = new Person( "John Doe" );
|
||||
entityManager.persist( person );
|
||||
log.info( "Entity is in persisted state" );
|
||||
|
||||
txn.commit();
|
||||
//end::flushing-auto-flush-commit-example[]
|
||||
} catch (RuntimeException e) {
|
||||
if ( txn != null && txn.isActive()) txn.rollback();
|
||||
throw e;
|
||||
} finally {
|
||||
if (entityManager != null) {
|
||||
entityManager.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlushAutoJPQL() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
log.info( "testFlushAutoJPQL" );
|
||||
//tag::flushing-auto-flush-jpql-example[]
|
||||
Person person = new Person( "John Doe" );
|
||||
entityManager.persist( person );
|
||||
entityManager.createQuery( "select p from Advertisement p" ).getResultList();
|
||||
entityManager.createQuery( "select p from Person p" ).getResultList();
|
||||
//end::flushing-auto-flush-jpql-example[]
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlushAutoJPQLOverlap() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
log.info( "testFlushAutoJPQLOverlap" );
|
||||
//tag::flushing-auto-flush-jpql-overlap-example[]
|
||||
Person person = new Person( "John Doe" );
|
||||
entityManager.persist( person );
|
||||
entityManager.createQuery( "select p from Person p" ).getResultList();
|
||||
//end::flushing-auto-flush-jpql-overlap-example[]
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlushAutoSQL() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
entityManager.createNativeQuery( "delete from Person" ).executeUpdate();;
|
||||
} );
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
log.info( "testFlushAutoSQL" );
|
||||
//tag::flushing-auto-flush-sql-example[]
|
||||
assertTrue(((Number) entityManager
|
||||
.createNativeQuery( "select count(*) from Person")
|
||||
.getSingleResult()).intValue() == 0 );
|
||||
|
||||
Person person = new Person( "John Doe" );
|
||||
entityManager.persist( person );
|
||||
|
||||
assertTrue(((Number) entityManager
|
||||
.createNativeQuery( "select count(*) from Person")
|
||||
.getSingleResult()).intValue() == 1 );
|
||||
//end::flushing-auto-flush-sql-example[]
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlushAutoSQLNativeSession() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
entityManager.createNativeQuery( "delete from Person" ).executeUpdate();;
|
||||
} );
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
log.info( "testFlushAutoSQLNativeSession" );
|
||||
//tag::flushing-auto-flush-sql-native-example[]
|
||||
assertTrue(((Number) entityManager
|
||||
.createNativeQuery( "select count(*) from Person")
|
||||
.getSingleResult()).intValue() == 0 );
|
||||
|
||||
Person person = new Person( "John Doe" );
|
||||
entityManager.persist( person );
|
||||
Session session = entityManager.unwrap(Session.class);
|
||||
|
||||
assertTrue(((Number) session
|
||||
.createSQLQuery( "select count(*) from Person")
|
||||
.uniqueResult()).intValue() == 0 );
|
||||
//end::flushing-auto-flush-sql-native-example[]
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlushAutoSQLSynchronization() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
entityManager.createNativeQuery( "delete from Person" ).executeUpdate();;
|
||||
} );
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
log.info( "testFlushAutoSQLSynchronization" );
|
||||
//tag::flushing-auto-flush-sql-synchronization-example[]
|
||||
assertTrue(((Number) entityManager
|
||||
.createNativeQuery( "select count(*) from Person")
|
||||
.getSingleResult()).intValue() == 0 );
|
||||
|
||||
Person person = new Person( "John Doe" );
|
||||
entityManager.persist( person );
|
||||
Session session = entityManager.unwrap( Session.class );
|
||||
|
||||
assertTrue(((Number) session
|
||||
.createSQLQuery( "select count(*) from Person")
|
||||
.addSynchronizedEntityClass( Person.class )
|
||||
.uniqueResult()).intValue() == 1 );
|
||||
//end::flushing-auto-flush-sql-synchronization-example[]
|
||||
} );
|
||||
}
|
||||
|
||||
//tag::flushing-auto-flush-jpql-entity-example[]
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
public Person() {}
|
||||
|
||||
public Person(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Entity(name = "Advertisement")
|
||||
public static class Advertisement {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String title;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
}
|
||||
//end::flushing-auto-flush-jpql-entity-example[]
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* 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.jpa.test.userguide.flush;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FlushModeType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import static org.hibernate.jpa.test.util.TransactionUtil.doInJPA;
|
||||
|
||||
/**
|
||||
* <code>CommitFlushTest</code> - Commit Flush Test
|
||||
*
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class CommitFlushTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
private static final Logger log = Logger.getLogger( CommitFlushTest.class);
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[]{
|
||||
Person.class,
|
||||
Phone.class,
|
||||
Advertisement.class,
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlushJPQL() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
log.info("testFlushJPQL");
|
||||
//tag::flushing-commit-flush-jpql-example[]
|
||||
Person person = new Person("John Doe");
|
||||
entityManager.persist(person);
|
||||
|
||||
entityManager.createQuery("select p from Advertisement p")
|
||||
.setFlushMode( FlushModeType.COMMIT)
|
||||
.getResultList();
|
||||
|
||||
entityManager.createQuery("select p from Person p")
|
||||
.setFlushMode( FlushModeType.COMMIT)
|
||||
.getResultList();
|
||||
//end::flushing-commit-flush-jpql-example[]
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlushSQL() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
entityManager.createNativeQuery("delete from Person")
|
||||
.executeUpdate();
|
||||
});
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
log.info("testFlushSQL");
|
||||
//tag::flushing-commit-flush-sql-example[]
|
||||
Person person = new Person("John Doe");
|
||||
entityManager.persist(person);
|
||||
|
||||
assertTrue(((Number) entityManager
|
||||
.createNativeQuery("select count(*) from Person")
|
||||
.getSingleResult()).intValue() == 1);
|
||||
//end::flushing-commit-flush-sql-example[]
|
||||
});
|
||||
}
|
||||
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@OneToMany(mappedBy = "person", cascade = CascadeType.ALL)
|
||||
private List<Phone> phones = new ArrayList<>();
|
||||
|
||||
public Person() {
|
||||
}
|
||||
|
||||
public Person(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<Phone> getPhones() {
|
||||
return phones;
|
||||
}
|
||||
|
||||
public void addPhone(Phone phone) {
|
||||
phones.add(phone);
|
||||
phone.setPerson(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Phone")
|
||||
public static class Phone {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
@ManyToOne
|
||||
private Person person;
|
||||
|
||||
private String number;
|
||||
|
||||
public Phone() {
|
||||
}
|
||||
|
||||
public Phone(String number) {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public Person getPerson() {
|
||||
return person;
|
||||
}
|
||||
|
||||
public void setPerson(Person person) {
|
||||
this.person = person;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Advertisement")
|
||||
public static class Advertisement {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String title;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* 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.jpa.test.userguide.flush;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import static org.hibernate.jpa.test.util.TransactionUtil.doInJPA;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* <code>ManualFlushTest</code> - Manual Flush Test
|
||||
*
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class ManualFlushTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
private static final Logger log = Logger.getLogger( ManualFlushTest.class);
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[]{
|
||||
Person.class,
|
||||
Phone.class,
|
||||
Advertisement.class,
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlushSQL() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
entityManager.createNativeQuery("delete from Person").executeUpdate();
|
||||
});
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
log.info("testFlushSQL");
|
||||
//tag::flushing-manual-flush-example[]
|
||||
Person person = new Person("John Doe");
|
||||
entityManager.persist(person);
|
||||
|
||||
Session session = entityManager.unwrap( Session.class);
|
||||
session.setFlushMode( FlushMode.MANUAL);
|
||||
|
||||
assertTrue(((Number) entityManager
|
||||
.createQuery("select count(id) from Person")
|
||||
.getSingleResult()).intValue() == 0);
|
||||
|
||||
assertTrue(((Number) session
|
||||
.createSQLQuery("select count(*) from Person")
|
||||
.uniqueResult()).intValue() == 0);
|
||||
//end::flushing-manual-flush-example[]
|
||||
});
|
||||
}
|
||||
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@OneToMany(mappedBy = "person", cascade = CascadeType.ALL)
|
||||
private List<Phone> phones = new ArrayList<>();
|
||||
|
||||
public Person() {
|
||||
}
|
||||
|
||||
public Person(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<Phone> getPhones() {
|
||||
return phones;
|
||||
}
|
||||
|
||||
public void addPhone(Phone phone) {
|
||||
phones.add(phone);
|
||||
phone.setPerson(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Phone")
|
||||
public static class Phone {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
@ManyToOne
|
||||
private Person person;
|
||||
|
||||
private String number;
|
||||
|
||||
public Phone() {
|
||||
}
|
||||
|
||||
public Phone(String number) {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public Person getPerson() {
|
||||
return person;
|
||||
}
|
||||
|
||||
public void setPerson(Person person) {
|
||||
this.person = person;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Advertisement")
|
||||
public static class Advertisement {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String title;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
INSERT INTO Person (name, id) VALUES ('John Doe', 1)
|
||||
|
||||
SELECT COUNT(*) FROM Person
|
|
@ -0,0 +1,2 @@
|
|||
--INFO: Entity is in persisted state
|
||||
INSERT INTO Person (name, id) VALUES ('John Doe', 1)
|
|
@ -0,0 +1,9 @@
|
|||
SELECT a.id AS id1_0_ ,
|
||||
a.title AS title2_0_
|
||||
FROM Advertisement a
|
||||
|
||||
INSERT INTO Person (name, id) VALUES ('John Doe', 1)
|
||||
|
||||
SELECT p.id AS id1_1_ ,
|
||||
p.name AS name2_1_
|
||||
FROM Person p
|
|
@ -0,0 +1,5 @@
|
|||
INSERT INTO Person (name, id) VALUES ('John Doe', 1)
|
||||
|
||||
SELECT p.id AS id1_1_ ,
|
||||
p.name AS name2_1_
|
||||
FROM Person p
|
|
@ -0,0 +1,9 @@
|
|||
SELECT a.id AS id1_0_ ,
|
||||
a.title AS title2_0_
|
||||
FROM Advertisement a
|
||||
|
||||
SELECT p.id AS id1_1_ ,
|
||||
p.name AS name2_1_
|
||||
FROM Person p
|
||||
|
||||
INSERT INTO Person (name, id) VALUES ('John Doe', 1)
|
|
@ -0,0 +1,3 @@
|
|||
INSERT INTO Person (name, id) VALUES ('John Doe', 1)
|
||||
|
||||
SELECT COUNT(*) FROM Person
|
|
@ -0,0 +1,5 @@
|
|||
SELECT COUNT(p.id) AS col_0_0_
|
||||
FROM Person p
|
||||
|
||||
SELECT COUNT(*)
|
||||
FROM Person
|
|
@ -0,0 +1,107 @@
|
|||
package org.hibernate.jpa.test.userguide.ql;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.jpa.test.util.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* <code>BulkTest</code> - Bulk JPQL Test
|
||||
*
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class BulkTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Customer.class
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdate() {
|
||||
final Calendar calendar = new GregorianCalendar();
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
entityManager.persist( new Customer( "Vlad" ) );
|
||||
entityManager.persist( new Customer( "Mihalcea" ) );
|
||||
} );
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
String oldName = "Vlad";
|
||||
String newName = "Mr. Vlad";
|
||||
|
||||
String jpqlUpdate = "update Customer c set c.name = :newName where c.name = :oldName";
|
||||
int updatedEntities = entityManager.createQuery( jpqlUpdate )
|
||||
.setParameter( "oldName", oldName )
|
||||
.setParameter( "newName", newName )
|
||||
.executeUpdate();
|
||||
assertEquals(1, updatedEntities);
|
||||
} );
|
||||
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
String oldName = "Mr. Vlad";
|
||||
String newName = "Vlad";
|
||||
|
||||
|
||||
String jpqlUpdate = "update Customer set name = :newName where name = :oldName";
|
||||
int updatedEntities = entityManager.createQuery( jpqlUpdate )
|
||||
.setParameter( "oldName", oldName )
|
||||
.setParameter( "newName", newName )
|
||||
.executeUpdate();
|
||||
assertEquals(1, updatedEntities);
|
||||
} );
|
||||
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
String oldName = "Vlad";
|
||||
|
||||
String jpqlDelete = "delete Customer c where c.name = :oldName";
|
||||
int updatedEntities = entityManager.createQuery( jpqlDelete )
|
||||
.setParameter( "oldName", oldName )
|
||||
.executeUpdate();
|
||||
assertEquals(1, updatedEntities);
|
||||
} );
|
||||
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
String oldName = "Mihalcea";
|
||||
|
||||
String jpqlDelete = "delete Customer where name = :oldName";
|
||||
int updatedEntities = entityManager.createQuery( jpqlDelete )
|
||||
.setParameter( "oldName", oldName )
|
||||
.executeUpdate();
|
||||
assertEquals(1, updatedEntities);
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity(name = "Customer")
|
||||
public static class Customer {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
public Customer() {
|
||||
}
|
||||
|
||||
public Customer(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue