views:

61

answers:

5

I've encountered a rather odd case in Java EE 6 where using the JPA EntityManager's find method along with an entity's primary id returns null, but using the Criteria API to select all entities with that id works fine.

Here is the code I'm using for find:

// Always returns null, even for records I know for sure are in there.
user = em.find(User.class, userId);

...and here's the code I'm using with the Criteria API:

CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<User> criteria = builder.createQuery(User.class);
Root<User> u = criteria.from(User.class);
TypedQuery<User> query = em.createQuery(
    criteria.select(u).where(builder.equal(u.get("id"), userId)));
user = query.getSingleResult();

Any idea why find returns null but Criteria finds the User? I tried these two alternate methods in the exact same spot in the program.

Here are the relevant portions of the User entity:

@Entity
@Table(name = "USERS")
@Access(AccessType.PROPERTY)
public class User implements Serializable {
    ...
    private Long id;
    ...
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_id_generator")
    @SequenceGenerator(name = "user_id_generator", sequenceName = "user_sequence", allocationSize = 1)
    @Column(name="id")
    public Long getId() {
        return this.id;
    }

    public void setId(Long id) {
        this.id = id;
    }
    ...
}
A: 

One reason could be that the "id" field has not been correctly marked as the id for the User entity.

bashflyng
+2  A: 

What provider are you using?

Where are you executing this find, in or out of a transaction? Are you flushing and clearing the EM prior to the find?

Using EclipseLink as a provider, and my own similar model, I am not able to reproduce this.

Assuming your provider can log SQL, are you seeing SQL going to the DB on the find? What does the SQL look like, and does it execute properly in SQL Plus etc...

Peter Krogh
I should be flushing the EM prior to the find? I'm using Hibernate as my provider.
cdmckay
I'm running it in a `@Stateless` EJB. The EM is decorated with a `@PersistanceContext(unitName = "xxx_persistence")`. I'm going to refer to the SQL logs and see what I can find.
cdmckay
Ok I checked out the SQL and was very surprised to see the difference between the two queries: the "find" version was doing a billion joins whereas the "criteria" query was only grabbing from the users table. Someone else wrote the entity files so I'll have to dig through those to find out what's causing this.
cdmckay
*"I should be flushing the EM prior to the find? I'm using Hibernate as my provider."* **No** (performing a query will flush pending changes).
Pascal Thivent
A: 

As a sanity check debug your code, taking the time before executing the find to run a manual query on the database yourself to ensure that an appropriate User record is present with the id you expect.

If it's not in the database, ensure that the entity manager has been flushed or the current transaction has been committed.

For instance, if you are using Hibernate as the provider, it is possible that the object is "persisted" merely in cache and the changes have not actually been pushed to the database. Accordingly, the criteria going through Hibernate's implementation will retrieve the object, but the entity manager find will not be able to locate the object.

apiri
This is a good suggestion but I know that it wasn't being cached because I could go look at in the database before I even started up the app.
cdmckay
+1  A: 

Double check that you are passing a Long in the following snippet:

// Always returns null, even for records I know for sure are in there.
user = em.find(User.class, userId);

If this doesn't help, activate SQL logging to see what is happening and compare the behavior in both cases.

Pascal Thivent
I debugged and checked that it was indeed a Long.
cdmckay
@cdmckay: I ran your code on my side and I can't reproduce (as expected to be honest). Tested with Hibernate EM 3.5.3-Final.
Pascal Thivent
Yeah, I think it has to do with how the User entity is annotated.
cdmckay
A: 

I figured out the problem. It was due to a field in the database being null where it should not have been permitted. This was due to me editing it by hand. After I added a value to that field, the problem went away.

cdmckay