Hallo zusammen
Ich denke wenn ihr kurz mal in den Code schaut könnt ihr mir nach kurzem Sagen was ich falsch mache aber irgend wie find ich es selber auch nach Tagen nicht raus.
Problem:
Ich habe ein Session Bean mit laufender CMT Transaktion in dem ich ein Entity Bean lade und verändere. Beim Commit der Transaktion schreibt mir Hibernate die Änderung jedoch nicht ohne expliziten Aufruf von Flush auf die DB. Warum???
Soweit ich das verstehe müsste doch das nun Hibernate mit JPA im EE automatisch machen?
Problem liegt im PatientRepositoryImpl.approvePatient wo ich das EntityBean über die Basisklasse lade, dann verändere und zurückgebe. Ich meinte eigentlich, dass beim Commit der Transaktion (Transaktion wird commited) die Änderungen gegen die DB geschrieben werden müssten. Liege ich da falsch?
Persistence.xml
Code:
<persistence 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_1_0.xsd"
version="1.0">
<!-- TODO switch to DataSource -->
<persistence-unit name="MedRec" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>jdbc/MedRecGlobalDataSourceXA</jta-data-source>
<class>com.bea.medrec.model.Address</class>
<class>com.bea.medrec.model.Administrator</class>
<class>com.bea.medrec.model.BaseEntity</class>
<class>com.bea.medrec.model.PersonName</class>
<class>com.bea.medrec.model.Patient</class>
<class>com.bea.medrec.model.Physician</class>
<class>com.bea.medrec.model.Prescription</class>
<class>com.bea.medrec.model.Record</class>
<class>com.bea.medrec.model.RegularUser</class>
<class>com.bea.medrec.model.User</class>
<class>com.bea.medrec.model.VersionedEntity</class>
<class>com.bea.medrec.model.VitalSigns</class>
<properties>
<!-- SQL stdout logging -->
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="use_sql_comments" value="true"/>
<!-- to prevent the ClassDefNotFound problem with weblogic -->
<property name="hibernate.query.factory_class" value="org.hibernate.hql.classic.ClassicQueryTranslatorFactory"/>
<property name="hibernate.c3p0.min_size" value="5"/>
<property name="hibernate.c3p0.max_size" value="20"/>
<property name="hibernate.c3p0.timeout" value="300"/>
<property name="hibernate.c3p0.max_statements" value="50"/>
<property name="hibernate.c3p0.idle_test_period" value="3000"/>
<property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.WeblogicTransactionManagerLookup"/>
<property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.CMTTransactionFactory"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.PointbaseDialect"/>
</properties>
</persistence-unit>
</persistence>
Code Session BeanCode:
@Stateless
public class PatientRepositoryImpl extends BaseUserRepositoryImpl<Patient> implements PatientRepository {
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public Patient approvePatient(Long patientId) {
Patient patient = find(patientId);
patient.approve();
return patient;
}
public int countBySsn(String ssn) {
String query = "Patient.countPatientBySsn";
return countByProperty(query, new Property("ssn", ssn));
}
public int countBySsnAndId(String ssn, Long id) {
String query = "Patient.countPatientBySsnAndId";
return countByProperties(query, new Property("ssn", ssn), new Property("id", id));
}
public int countByUsernameAndPasswordAndStatus(String username, String password, Patient.Status status) {
String query = "Patient.countPatientByUsernameAndPasswordAndStatus";
return countByProperties(query, new Property("username", username), new Property("password", password),
new Property("status", status.toString()));
}
public List<Patient> findByLastNameAndStatus(String lastName, Patient.Status status) {
String query = "Patient.findPatientByLastNameAndStatus";
return findByProperties(query, new Property("lastName", lastName),
new Property("status", status.toString()));
}
public Patient findBySsnAndStatus(String ssn, Patient.Status status) {
String query = "Patient.findPatientBySsnAndStatus";
return findByUniqueProperties(query, new Property("ssn", ssn), new Property("status", status.toString()));
}
public List<Patient> findByStatus(Patient.Status status) {
String query = "Patient.findPatientByStatus";
return findByProperty(query, new Property("status", status.toString()));
}
public Patient findByUsernameAndPasswordAndStatus(String username, String password, Patient.Status status) {
String query = "Patient.findPatientByUsernameAndPasswordAndStatus";
return findByUniqueProperties(query, new Property("username", username),
new Property("password", password), new Property("status", status.toString()));
}
protected String getQueryForCountByUsername() {
return "Patient.countPatientByUsername";
}
protected String getQueryForCountByUsernameAndPassword() {
return "Patient.countPatientByUsernameAndPassword";
}
protected String getQueryForFindByUsernameAndPassword() {
return "Patient.findPatientByUsernameAndPassword";
}
}
Basisklassen:
Code:
/**
* @author Copyright (c) 2007 by BEA Systems. All Rights Reserved.
* @author <a href="mailto:shli@bea.com">Li Shen</a>
*/
public abstract class BaseUserRepositoryImpl<T extends User> extends EntityRepositorySupport<T, Long> implements
UserRepository<T> {
public int countByUsername(String username) {
return countByProperty(getQueryForCountByUsername(), new Property("username", username));
}
public int countByUsernameAndPassword(String username, String password) {
return countByProperties(getQueryForCountByUsernameAndPassword(), new Property("username", username),
new Property("password", password));
}
public T findByUsernameAndPassword(String username, String password) {
return findByUniqueProperties(getQueryForFindByUsernameAndPassword(), new Property("username", username),
new Property("password", password));
}
protected abstract String getQueryForCountByUsername();
protected abstract String getQueryForCountByUsernameAndPassword();
protected abstract String getQueryForFindByUsernameAndPassword();
}
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
public abstract class EntityRepositorySupport<T, ID extends Serializable> implements EntityRepository<T, ID> {
@SuppressWarnings("unchecked")
private final Class<T> entityClass = ClassUtils.getGenericArgumentType(getClass());
// TODO customize persistence unit?
@PersistenceContext
private EntityManager entityManager;
protected int countByProperties(String namedQuery, Object... propertyValues) {
Long count = (Long) createNamedQuery(namedQuery, propertyValues).getSingleResult();
return count.intValue();
}
protected int countByProperties(String namedQuery, Property... properties) {
return countByProperties(namedQuery, (Object[]) properties);
}
protected int countByProperty(String namedQuery, Object propertyValue) {
return countByProperties(namedQuery, propertyValue);
}
protected int countByProperty(String namedQuery, String propertyName, Object propertyValue) {
return countByProperties(namedQuery, new Property(propertyName, propertyValue));
}
private Query createNamedQuery(String namedQuery, Object... propertyValues) {
Query query = getEntityManager().createNamedQuery(namedQuery);
int i = 1;
for (Object propertyValue : propertyValues) {
if (propertyValue instanceof Property) {
Property property = (Property) propertyValue;
query.setParameter(property.name, property.value);
}
else {
query.setParameter(i, propertyValue);
}
i++;
}
return query;
}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void delete(ID id) {
// TODO maybe use a query instead
entityManager.remove(find(id));
}
public T find(ID id) {
return entityManager.find(entityClass, id);
}
@SuppressWarnings("unchecked")
protected List<T> findByProperties(String namedQuery, Object... propertyValues) {
return createNamedQuery(namedQuery, propertyValues).getResultList();
}
protected List<T> findByProperties(String namedQuery, Property... properties) {
return findByProperties(namedQuery, (Object[]) properties);
}
protected List<T> findByProperty(String namedQuery, Object propertyValue) {
return findByProperties(namedQuery, propertyValue);
}
protected List<T> findByProperty(String namedQuery, String propertyName, Object propertyValue) {
return findByProperties(namedQuery, new Property(propertyName, propertyValue));
}
@SuppressWarnings("unchecked")
protected T findByUniqueProperties(String namedQuery, Object... propertyValues) {
try {
return (T) createNamedQuery(namedQuery, propertyValues).getSingleResult();
}
catch (NoResultException e) {
return null;
}
}
protected T findByUniqueProperties(String namedQuery, Property... properties) {
return findByUniqueProperties(namedQuery, (Object[]) properties);
}
protected T findByUniqueProperty(String namedQuery, Object propertyValue) {
return findByUniqueProperties(namedQuery, propertyValue);
}
protected T findByUniqueProperty(String namedQuery, String propertyName, Object propertyValue) {
return findByUniqueProperties(namedQuery, new Property(propertyName, propertyValue));
}
protected EntityManager getEntityManager() {
return entityManager;
}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void save(T entity) {
entityManager.persist(entity);
}
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public T update(T entity) {
T retVal = entityManager.merge(entity);
//entityManager.flush();
return retVal;
}
}
Entity Bean:Code:
@Entity
@Table(name = "patients"/*, uniqueConstraints = {@UniqueConstraint(columnNames = {"email", "username", "ssn"})}*/)
@NamedQueries( {
@NamedQuery(name = "Patient.countPatientByUsernameAndPasswordAndStatus", query = "SELECT COUNT(p) FROM Patient p WHERE p.username = :username AND p.password = :password AND p.status = :status"),
@NamedQuery(name = "Patient.countPatientByUsernameAndPassword", query = "SELECT COUNT(p) FROM Patient p WHERE p.username = :username AND p.password = :password"),
@NamedQuery(name = "Patient.countPatientByUsername", query = "SELECT COUNT(p) FROM Patient p WHERE p.username = :username"),
@NamedQuery(name = "Patient.countPatientBySsnAndId", query = "SELECT COUNT(p) FROM Patient p WHERE p.ssn = :ssn AND p.id <> :id"),
@NamedQuery(name = "Patient.countPatientBySsn", query = "SELECT COUNT(p) FROM Patient p WHERE p.ssn = :ssn"),
@NamedQuery(name = "Patient.findPatientByStatus", query = "SELECT p FROM Patient p WHERE p.status = :status"),
@NamedQuery(name = "Patient.findPatientBySsnAndStatus", query = "SELECT p FROM Patient p WHERE p.ssn = :ssn AND p.status = :status"),
@NamedQuery(name = "Patient.findPatientByLastNameAndStatus", query = "SELECT p FROM Patient p WHERE p.name.lastName = :lastName AND p.status = :status"),
@NamedQuery(name = "Patient.findPatientByUsernameAndPasswordAndStatus", query = "SELECT p FROM Patient p WHERE p.username = :username AND p.password = :password AND p.status = :status"),
@NamedQuery(name = "Patient.findPatientByUsernameAndPassword", query = "SELECT p FROM Patient p WHERE p.username = :username AND p.password = :password") })
public class Patient extends RegularUser {
private static final long serialVersionUID = 313728838021028177L;
private Address address = new Address();
private Date dob;
@Enumerated(EnumType.STRING)
private Gender gender;
// No setter and getter... Now used to do cascading =>
// husl => this is not acording the spec. The spec states that the other side is always the owning side
@OneToMany(cascade = CascadeType.ALL, mappedBy = "patient")
private List<Record> records;
private String ssn;
@Enumerated(EnumType.STRING)
private Patient.Status status = Patient.Status.REGISTERED;
public void approve() {
setStatus(Patient.Status.APPROVED);
}
@PreUpdate
public void beforeUpdate() {
Logger.getLogger(this.getClass()).log(Priority.WARN, "Before update of patient");
}
public void deny() {
setStatus(Patient.Status.DENIED);
}
public Address getAddress() {
return address;
}
public Date getDob() {
return dob;
}
public Gender getGender() {
return gender;
}
public String getSsn() {
return ssn;
}
public Patient.Status getStatus() {
return status;
}
public boolean isApproved() {
return Patient.Status.APPROVED.equals(getStatus());
}
public boolean isDenied() {
return Patient.Status.DENIED.equals(getStatus());
}
@PostUpdate
public void postUpdate() {
Logger.getLogger(this.getClass()).log(Priority.WARN, "After update of patient");
}
public void setAddress(Address address) {
this.address = address;
}
public void setDob(Date dob) {
this.dob = dob;
}
public void setGender(Gender gender) {
this.gender = gender;
}
public void setSsn(String ssn) {
this.ssn = ssn;
}
public void setStatus(Patient.Status status) {
this.status = status;
}
public enum Gender {
FEMALE, MALE
}
public enum Status {
APPROVED, DENIED, REGISTERED
}
}
Seht ihr was ich falsch mache?