Thanks Christian! That are good news... Especially, your future planning 
regarding "TransactionTemplate" sounds really interesting.

Can you plase provide a small example for your alternative solutions. How can I 
obtain a "UserTransaction" to create the transaction?

Best regards,
Jens

Gesendet: Samstag, 22. April 2017 um 13:22 Uhr
Von: "Christian Schneider" <[email protected]>
An: [email protected]
Betreff: Re: Consistent entity updates without exposing JpaTemplate

For now this is a good pattern. I plan to add  a pure TransactionTemplate or 
similar to cover this case outside of JPATemplate.
 
Alternatively you can inject a UserTransaction and use it to create the 
transaction.
 
Christian
 
2017-04-21 16:49 GMT+02:00 Jens Offenbach 
<[email protected][mailto:[email protected]]>:Hallo,
I am sorry, but I am still in trouble with JpaTemplate and API design. I am 
trying to hide JpaTemplate in my service implementation, but I am not sure, if 
this is the recommended approach. Unfortuantely, I cannot find any complex 
examples in the web.

Let me explain the problem with the help of the TaskService example 
(https://github.com/apache/aries/blob/trunk/jpa/examples/tasklist-ds/src/main/java/org/apache/aries/jpa/example/tasklist/ds/impl/TaskServiceImpl.java[https://github.com/apache/aries/blob/trunk/jpa/examples/tasklist-ds/src/main/java/org/apache/aries/jpa/example/tasklist/ds/impl/TaskServiceImpl.java]):

Task task = taskService.getTask(1);
task.setTitle("New Title#1");

Both calls must be done under transaction control to keep the database 
consistent (Thanks Christian), so the only correct way would be:

jpa.tx(em -> {
    Task task = taskService.getTask(1);
    task.setTitle("New Title#1");
});

The problem is, that service users must have the JpaTemplate reference for 
consistent entity updates. The only way to hide JpaTemplate would be to extend 
TaskService like this:

public interface TaskService {

    void tx(Runnable runnable);

    Task getTask(Integer id);

    void addTask(Task task);

    void updateTask(Task task);

    void deleteTask(Integer id);

    Collection<Task> getTasks();

}

@Component
public class TaskServiceImpl implements TaskService {

    @Reference(target = "(osgi.unit.name[http://osgi.unit.name]=tasklist)")
    private JpaTemplate jpa;

    @Override
    public void tx(Runnable runnable) {
        jpa.tx(em -> runnable.run());
    }

}

The resulting user code that updates an entity consistently (hopefully) would 
look like this:

@Component(immediate = true)
public class TasklistUpdater {

    @Reference
    TaskService taskService;

    @Activate
    public void addDemoTask() {
        if (taskService.getTask(1) == null) {
            Task task = new Task();
            task.setId(1);
            task.setTitle("Task1");
            taskService.addTask(task);
        }
        updateDemoTask();
    }

    private void updateDemoTask() {
        taskService.tx(() -> {
            Task task = taskService.getTask(1);
            task.setDescription("A description");
            task.setTitle("A title");
        });
    }

}

I am not sure, if this approach works as expected and if JpaTemplate calls can 
be nested as shown above. What about overhead?

Are there any best practices known regarding API design in respect to 
JpaTemplate?

I am thankful for any comments or ideas for improvement?

Thank you very much,
Jens
  
 --

--
Christian Schneider
http://www.liquid-reality.de[https://owa.talend.com/owa/redir.aspx?C=3aa4083e0c744ae1ba52bd062c5a7e46&URL=http%3a%2f%2fwww.liquid-reality.de]

Open Source Architect
http://www.talend.com[https://owa.talend.com/owa/redir.aspx?C=3aa4083e0c744ae1ba52bd062c5a7e46&URL=http%3a%2f%2fwww.talend.com]

Reply via email to