We have a Java EE application running in Glassfish 3.1, where we have our JPA models (using EclipseLink) organized like this:
Customer
-> String firstName
-> String lastName
-> Address adress
-> List<Attribute> attributes
-> Int age
Address
-> String street
-> Int zip
-> String city
Attribute
-> String code
-> String name
Most of the attributes like firstName and lastName are annotated with @Column(nullable=false). Now we do:
@Stateless
public class CustomerController {
@PersistenceContext(unitName = "CustomerService")
private EntityManager em;
@EJB
private AttributeController attributeController;
public String createCustomer() {
Customer customer = new Customer();
customer.firstName = "Hans";
customer.lastName = "Peter";
customer.address = new Address();
customer.adress.street = ...
customer.attributes = new ArrayList<Attribute>();
customer.attributes.add(attributeController.getByCode("B"));
customer.attributes.add(attributeController.getByCode("T"));
customer.age = 27;
em.persist(customer);
}
}
This works for small classes like the one above, but we have now introduced more objects which are related to the customer like attributes with a @OneToMany and are loaded from other @EJBs like the attributeController.
For “big” models it now seems like a transaction is commited right in the process of still loading related objects, since we get a ERROR: null value in column "age" violates not-null constraint. Since we use JTA container managed transactions and have not set @TransactionAttribute to something other than the default REQUIRED, we do not control the transaction directly and have no idea what is going wrong here.
Is there a certain amount of “units of work” that can be oben before a commit takes place? Are we loading the related objects wrong? Have we made some other major mistake?
As soon as we omit the nullable=false constraints, everything works fine…
Your entities are probably getting auto-flushed when queries are occurring. According to the JavaDocs for
FlushModeType:Basically, if you do a query, and any of your uncommitted entities (which don’t have all their members set yet) would be eligible to be a result of that query, then the persistence implementation must flush them to the database (or do something with equivalent effect), thus causing an exception to be thrown because the nullable constraints are invalid. It seems a little unintuitive to me, too. I wouldn’t have known about it if we hadn’t run into a very similar issue in our application.
It sounds like you just want to use
EntityManager.setFlushMode()orQuery.setFlushMode()to set the flush mode toCOMMIT.