Usage
Persist
Use an n-arg constructor, eg:
Customer cust = repositoryService.detachedEntity(
new Customer("Freddie", "Mercury"));
repositoryService.persist(cust);
rather than the deprecated version that takes a type:
Customer cust = repositoryService.detachedEntity(Customer.class);
cust.setFirstName("Freddie");
cust.setLastName("Mercury");
repositoryService.persist(cust);
You should be aware that by default the framework queues up calls to #persist() and #remove(). These are then executed either when the request completes (and the transaction commits), or if the queue is flushed. This can be done either implicitly by the framework, or as the result of a direct call to TransactionService#flushTransaction.
By default the framework itself will cause #flush() to be called whenever a query is executed by way of #allMatches(Query).
However, this behaviour can be disabled using the Other
persistAndFlush(…), removeAndFlush(…)
In some cases, such as when using managed properties and collections for implementing 1-1, 1-n, or m-n relationships, the developer needs to invoke flush() to send the changes to the persistence mechanism.
These managed properties and collections and then updated.
The persistAndFlush(…) and removeAndFlush(…) methods save the developer from having to additionally call the flush(…) method after calling persist() or remove().
For example, the following code requires a flush to occur, so uses these methods:
public abstract class Warehouse extends SalesVIPEntity<Marketplace> {
@Persistent(mappedBy = "marketplace", dependentElement = "true")
@Getter @Setter
SortedSet<MarketplaceExcludedProduct> excludedProducts =
new TreeSet<MarketplaceExcludedProduct>();
@Action(semantics = SemanticsOf.IDEMPOTENT)
public MarketplaceExcludedProduct addExcludedProduct(final Product product) {
val marketplaceExcludedProduct = findExcludedProduct(product);
if (marketplaceExcludedProduct == null) {
marketplaceExcludedProduct =
repositoryService.detachedEntity(
new MarketplaceExcludedProduct.builder()
.marketPlace(this)
.product(product)
.build());
}
repositoryService.persistAndFlush(marketplaceExcludedProduct); (1)
return marketplaceExcludedProduct;
}
@Action(semantics = SemanticsOf.IDEMPOTENT)
public void removeExcludedProducts(final Product product) {
val marketplaceExcludedProduct = findExcludedProduct(product);
if (marketplaceExcludedProduct != null) {
repositoryService.removeAndFlush(marketplaceExcludedProduct);
}
}
...
}
| 1 | Needed for updating the managed properties and collections. |
On the “addExcludedProduct()” action, if the user didn’t flush, the following test would fail because the managed collection would not containing the given product:
@Test
public void addExcludedProduct() {
// given
final AmazonMarketplace amazonMarketplace = this.wrapSkipRules(
this.marketplaceRepository).findOrCreateAmazonMarketplace(
AmazonMarketplaceLocation.FRANCE);
final Product product = this.wrap(this.productRepository)
.createProduct(UUID.randomUUID().toString(), UUID.randomUUID().toString());
// when
this.wrap(amazonMarketplace).addExcludedProduct(product);
// then
Assertions.assertThat(
this.wrapSkipRules(amazonMarketplace).findAllProductsExcluded()
).contains(product); (1)
}
| 1 | this would fail. |
Named queries and xxxMatches(…)
There are two subtypes of the Query API, namely NamedQuery and AllInstancesQuery.
The former is the more important, as it identifies a named query and a set of parameter/argument tuples, and is executed server-side.
For example, using JDO a ToDoItem could be annotated:
@javax.jdo.annotations.Queries( {
@javax.jdo.annotations.Query(
name = "findByAtPathAndComplete", language = "JDOQL", (1)
value = "SELECT "
+ "FROM todoapp.dom.module.todoitem.ToDoItem "
+ "WHERE atPath.indexOf(:atPath) == 0 " (2)
+ " && complete == :complete"), (3)
// ...
})
public class ToDoItem ... {
// ...
}
| 1 | name of the query |
| 2 | defines the atPath parameter |
| 3 | defines the complete parameter |
This JDO query definitions are used in the ToDoItemRepositoryImplUsingJdoql service:
import org.springframework.stereotype.Service;
@Service
public class ToDoItemRepositoryImplUsingJdoql implements ToDoItemRepositoryImpl {
@Programmatic
public List<ToDoItem> findByAtPathAndCategory(final String atPath, final Category category) {
return repositoryService.allMatches(
Query.named(ToDoItem.class,
"findByAtPathAndCategory", (1)
"atPath", atPath, (2)
"category", category)); (3)
}
...
@javax.inject.Inject
RepositoryService repositoryService;
}
| 1 | corresponds to the "findByAtPathAndCategory" JDO named query |
| 2 | provide argument for the atPath parameter.
The pattern is parameter, argument, parameter, argument, … and so on. |
| 3 | provide argument for the category parameter.
The pattern is parameter, argument, parameter, argument, … and so on. |
|
If using JPA, it is also possible to use the Spring Data repositories, using JpaSupportService. |
|
If using JDO/DataNucleus, it is also possible to use the DataNucleus type-safe query API, see JdoSupportService. |