[#object-management-crud]
= Object Management (CRUD)

:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR  CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
:page-partial:


This chapter shows the idioms for creating, reading, updating and deleting xref:userguide:fun:overview.adoc#domain-entities[domain entities].
The main domain services used for this are xref:refguide:applib:index/services/repository/RepositoryService.adoc[RepositoryService] and xref:refguide:applib:index/services/factory/FactoryService.adoc[FactoryService].


[[instantiating]]
== Instantiating

Domain entities can be instantiated using the xref:refguide:applib:index/services/factory/FactoryService.adoc[FactoryService] provided by the framework.
For example:

[source,java]
----
Customer customer = factoryService.detachedEntity(Customer.class);
----

The returned domain entity is not persistent and is unknown to the ORM; hence "detached".

When the framework instantiates the object, all services are injected into the framework, and an `ObjectCreatedEvent` xref:userguide:fun:overview.adoc#lifecycle-events[lifecycle event] will also be emitted.

You may prefer however for your domain entities to have regular constructor defining their minimum set of mandatory properties.
For example:

[source,java]
----
public class Customer {

    public Customer(String reference, String firstName, String lastName) {
        // ...
    }

    // ...
}
----

In such cases, the domain object cannot be instantiated using xref:refguide:applib:index/services/factory/FactoryService.adoc[FactoryService].
Instead the xref:refguide:applib:index/services/inject/ServiceInjector.adoc[ServiceInjector] service can be used to inject services:

[source,java]
----
Customer customer = new Customer(reference, firstName, lastName);
factoryService.detachedEntity(customer);
----

If you prefer, this can be performed in one step:

[source,java]
----
Customer customer = factoryService.detachedEntity(
                        new Customer(reference, firstName, lastName));
----

Note though that this does _not_ raise any lifecycle event.


[[persisting]]
== Persisting

Once a domain entity has been instantiated and initialized, it can be persisted using the xref:refguide:applib:index/services/repository/RepositoryService.adoc[RepositoryService].

For example:

[source,java]
----
Customer customer = ...

repositoryService.persist(customer);
----

If using the no-arg form to instantiate the entity, then (to save having to inject the `FactoryService` as well), the `RepositoryService` can also be used to instantiate.
This gives rise to this common idiom:

[source,java]
----
Customer customer = repositoryService.instantiate(Customer.class);
customer.setReference(reference);
customer.setFirstName(firstName);
customer.setLastName(lastName);
...
repositoryService.persist(customer);
----

On the other hand, there is often little need to inject services into the domain entity between its instantiation and persistence.
If the domain entity has an N-arg constructor, then the code is often simpler:

[source,java]
----
Customer customer = repositoryService.persist(new Customer(reference, name, lastname));
----

Note that the `persist()` returns the object passed to it.

=== Eager Persistence

It's worth being aware that the framework does _not_ eagerly persist the object.
Rather, it queues up an internal command structure representing the object persistence request.
This is then executed either at the end of the transaction, or if a xref:userguide:fun:domain-entities-and-services.adoc#finding[query is run], or if the internal queue is manually flushed using xref:refguide:applib:index/services/xactn/TransactionService.adoc[TransactionService]'s `flush()` method.
Flushing also happens when a repository query is executed, so that the pending persist operation is performed first.
Generally therefore the lazy persistence approach works well enough.

Nevertheless, if you want to ensure that the persist command is flushed immediately, you can use:

[source,java]
----
repositoryService.persistAndFlush(customer);
----

When an object is persisted the framework will emit `ObjectPersistingEvent` and `ObjectPersistedEvent` xref:userguide:fun:overview.adoc#lifecycle-events[lifecycle events].

=== Persistence by Reachability (JDO)

If using xref:pjdo:ROOT:about.adoc[JDO/DataNucleus], it is possible to configure ORM to automatically persist domain entities if they are associated with other already-persistent entities.
This avoid the need to explicitly call "persist".

This is done using xref:refguide:config:sections/datanucleus.adoc#datanucleus.persistence-by-reachability-at-commit[persistence-by-reachability] configuration property:

[source,ini]
.application.properties
----
datanucleus.persistence-by-reachability-at-commit=true
----

One downside is that the code is arguably less easy to debug, and there may be performance implications.


[[finding]]
== Finding Objects

Retrieving domain entities depends on the ORM, though the xref:refguide:applib:index/services/repository/RepositoryService.adoc[RepositoryService] can be used as an abstraction over either if required.


[[finding-jpa]]
=== Finding Objects (JPA)

The easiest way to retrieve domain entities if using JPA is to leverage the capabilities of Spring Data.

For example, simply by declaring this interface:

[source,java]
----
public interface UserRepository extends Repository<User, Long> {

  List<User> findByEmailAddressAndLastname(String emailAddress, String lastname);
}
----

and Spring Data will create an implementation based on naming conventions.
See the link:https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#reference[Spring Data] documentation for further details.

It is also possible to declare JPQL queries , either on the repository method (using `javax.persistence.Query`) or on the entity (using `javax.persistence.NamedQuery`).

On the entity, declare a named query, eg:

[source,java]
----
@javax.persistence.Entity
@javax.persistence.NamedQueries({
    @javax.persistence.NamedQuery(          // <.>
        name = "Customer.findByNameLike",   // <.>
        query = "SELECT c " +               // <.>
                "FROM Customer c " +        // <.>
                "WHERE c.name LIKE :name"   // <.>
    )
    })
...
public class Customer {
    // ...
}
----
<.> There may be several `@NamedQuery` annotations, nested within a `@NamedQueries` annotation, defining queries using JPQL.
<.> Defines the name of the query.
<.> The definition of the query, using JPQL syntax.
<.> The table name
<.> The predicate, expressed using SQL syntax.

and in the corresponding repository, use xref:refguide:applib:index/services/repository/RepositoryService.adoc[RepositoryService]:

[source,java]
----
import org.springframework.stereotype.Repository;
import lombok.RequiredArgsConstructor;

@Repository
@RequiredArgsConstructor(onConstructor_ = {@Inject} )
public class CustomerRepository {

    private final RepositoryService repositoryService;

    public List<Customer> findByName(String name) {
        return repositoryService.allMatches(                            // <.>
                Query.named(Customer.class, "Customer.findByNameLike")  // <.>
                     .withParameter("name", "%" + name + "%");          // <.>
    }

}
----
<.> The xref:refguide:applib:index/services/repository/RepositoryService.adoc[RepositoryService] is a generic facade over the ORM API.
<.> Specifies the class that is annotated with @NamedQuery, along with the `@NamedQuery#name` attribute
<.> The `:name` parameter in the query JPQL string, and its corresponding value


[[finding-jdo]]
=== Finding Objects (JDO)


In the case of xref:pjdo:ROOT:about.adoc[JDO/DataNucleus], it typically requires a JDOQL query defined on the domain entity, and a corresponding repository service for that domain entity type.
This repository calls the framework-provided xref:refguide:applib:index/services/repository/RepositoryService.adoc[RepositoryService] to actually submit the query.

For example:

[source,java]
----
@javax.jdo.annotations.PersistenceCapable
@javax.jdo.annotations.Queries({
    @javax.jdo.annotations.Query(                       // <.>
        name = "findByName",                            // <.>
        value = "SELECT "                               // <.>
                + "FROM com.mydomain.myapp.Customer "   // <.>
                + "WHERE name.indexOf(:name) >= 0 ")    // <.>
})
...
public class Customer {
    // ...
}
----
<.> There may be several `@Query` annotations, nested within a `@Queries` annotation, defining queries using JDOQL.
<.> Defines the name of the query.
<.> The definition of the query, using JDOQL syntax.
<.> The fully-qualified class name.
Must correspond to the class on which the annotation is defined (the framework checks this automatically on bootstrapping).
<.> The predicate, expressed using Java syntax.
In this particular query, is an implementation of a LIKE "name%" query.

and in the corresponding repository, use xref:refguide:applib:index/services/repository/RepositoryService.adoc[RepositoryService]:

[source,java]
----
import org.springframework.stereotype.Repository;
import lombok.RequiredArgsConstructor;

@Repository
@RequiredArgsConstructor(onConstructor_ = {@Inject} )
public class CustomerRepository {

    private final RepositoryService repositoryService;

    public List<Customer> findByName(String name) {
        return repositoryService.allMatches(                // <.>
                Query.named(Customer.class, "findByName")   // <.>
                     .withParameter("name", name);          // <.>
    }

}
----
<.> The xref:refguide:applib:index/services/repository/RepositoryService.adoc[RepositoryService] is a generic facade over the ORM API.
<.> Specifies the class that is annotated with @Query, along with the `@Query#name` attribute
<.> The `:name` parameter in the query JDOQL string, and its corresponding value

Whenever a query is submitted, the framework will automatically "flush" any pending changes.
This ensures that the database query runs against an up-to-date table so that all matching instances (with respect to the current transaction) are correctly retrieved.

When an object is loaded from the database the framework will emit `ObjectLoadedEvent` xref:userguide:fun:overview.adoc#lifecycle-events[lifecycle event].

=== Type-safe queries

DataNucleus also supports type-safe queries; these can be executed using the xref:refguide:persistence:index/jdo/applib/services/JdoSupportService.adoc[JdoSupportService] (JDO-specific) domain service.

See xref:refguide:persistence:index/jdo/applib/services/JdoSupportService.adoc#type-safe-jdoql-queries[JdoSupportService] for further details.

[[updating]]
== Updating Objects

There is no specific API to update a domain entity.
Rather, the ORM (DataNucleus) automatically keeps track of the state of each object and will update the corresponding database rows when the transaction completes.

That said, it is possible to "flush" pending changes:

* xref:refguide:applib:index/services/xactn/TransactionService.adoc[TransactionService] acts at the Apache Isis layer, and flushes any pending object persistence or object deletions

* (if using xref:pjdo:ROOT:about.adoc[JDO/DataNucleus]), the xref:refguide:persistence:index/jdo/applib/services/JdoSupportService.adoc[JdoSupportService] domain service can be used reach down to the underlying JDO API, and perform a flush of pending object updates also.

When an object is updated the framework will emit `ObjectUpdatingEvent` and `ObjectUpdatedEvent` xref:userguide:fun:overview.adoc#lifecycle-events[lifecycle events].

[[deleting]]
== Deleting Objects

:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR  CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
:page-partial:

Domain entities can be deleted using xref:refguide:applib:index/services/repository/RepositoryService.adoc[RepositoryService].
For example:

[source,java]
----
Customer customer = ...
repositoryService.remove(customer);
----

It's worth being aware that (as for persisting new entities) the framework does _not_ eagerly delete the object.
Rather, it queues up an internal command structure representing the object deletion request.
This is then executed either at the end of the transaction, or if a xref:userguide:fun:domain-entities-and-services.adoc#finding[query is run], or if the internal queue is manually flushed using xref:refguide:applib:index/services/xactn/TransactionService.adoc[TransactionService]'s `flush()` method.

Alternatively, you can use:

[source,java]
----
repositoryService.removeAndFlush(customer);
----

to eagerly perform the object deletion from the database.

When an object is deleted the framework will emit `ObjectRemovingEvent` xref:userguide:fun:overview.adoc#lifecycle-events[lifecycle event].



