brmeyer/HibernateOSGi

Changes on persistent entity are not saved automatically

Closed this issue · 0 comments

Hi @brmeyer.

I've been able to configure and deploy a container-managed JPA application with Hibernate on a Karaf 2.3.x. I've followed your documentation (great work!!!) but unfortunately I've found the following issue:

When I want to save changes on a persistent entity inside a JTA transaction, I must call "flush" method manually from entity manager. It does not flushed automatically at the end of transaction as a normal JPA application.

This is my configuration:

persistence.xml
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    <persistence-unit name="mknotificationsUnit" transaction-type="JTA">
        <jta-data-source>osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=jdbc/testDb)</jta-data-source>
        <properties>
            <property name="hibernate.format_sql" value="true" />
            <property name="hibernate.hbm2ddl.auto" value="update" />
            <property name="hibernate.archive.autodetection" value="class" />
            <property name="hibernate.transaction.flush_before_completion" value="true" />
        </properties>
    </persistence-unit>
</persistence>
datasource.xml
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0">
    <bean id="mkDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost/mknotifications" />
        <property name="username" value="xxx" />
        <property name="password" value="xxx" />
    </bean>
    <service ref="mkDataSource" interface="javax.sql.DataSource">
        <service-properties>
            <entry key="osgi.jndi.service.name" value="jdbc/testDb" />
        </service-properties>
    </service>
</blueprint>
blueprint.xml
<bean id="notificationsHandler" class="com.proof.NotificationsHandlerImpl">
    <jpa:context property="entityManager" unitname="mknotificationsUnit" />
    <tx:transaction method="getOrCreate" />
</bean>
service method
// This method is transactional as you can see on configuration
public Notification getOrCreate(URI service, URI recipient) {
    Notification notification = null;

    try {
        TypedQuery < Notification > query = entityManager.createNamedQuery(Notification.NQ_UNIQUE, Notification.class);
        query.setParameter("recipientUri", recipient.toString());
        query.setParameter("serviceUri", service.toString());

        // Query is executed without problems
        notification = query.getSingleResult();
    } catch (NoResultException e) {
        notification = new Notification();
        notification.setService(service);
        notification.setRecipient(recipient);

        // Entity is persisted as I want
        entityManager.persist(notification);
    }

    // I update "lastChange" field
    // but this change is not persisted automatically. 
    notification.setLastChange(new Date());
    return notification;
}
entity
@Entity
@Table(name = "notification", uniqueConstraints = {@UniqueConstraint(name = "uq_recipient_service", columnNames = {"recipient", "service" }) })
@NamedQueries({
        @NamedQuery(name = "findUniqueNotification", query = "select n from Notification n where n.recipient = :recipientUri and n.service = :serviceUri"),
        @NamedQuery(name = "findNotificationsByRecipient", query = "select n from Notification n where n.recipient = :recipientUri order by n.service asc") })
public class Notification extends GenericEntity {

    private static final String URI_SCHEMA = "notification";

    // Named Queries
    public static final String NQ_UNIQUE = "findUniqueNotification";
    public static final String NQ_BY_RECIPIENT = "findNotificationsByRecipient";

    @Column(nullable = false)
    private String recipient;

    @Column(nullable = false)
    private String service;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(nullable = false, updatable = false)
    private Date created;

    @Temporal(TemporalType.TIMESTAMP)
    @Column
    private Date lastChange;

    public String getRecipient() {
        return recipient;
    }

    public void setRecipient(String recipient) {
        this.recipient = recipient;
    }

    public String getService() {
        return service;
    }

    public void setService(String service) {
        this.service = service;
    }

    public Date getLastChange() {
        return lastChange;
    }

    public void setLastChange(Date lastChange) {
        this.lastChange = lastChange;
    }

    @PrePersist
    protected void prePersist() {
        created = new Date();
    }
}