cdmckay
cdmckay

Reputation: 32290

EntityManager.find can't find entity, but using the Criteria API does

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;
    }
    ...
}

Upvotes: 7

Views: 18880

Answers (6)

pkudlacik
pkudlacik

Reputation: 31

I confirm the solution. The same thing happened to me. I had collumns marked as NOT NULL, then during test in my app I switched the limitation off in the database for two collumns (foreign keys), however not changing the (optional = false) attribute of @ManyToOne relationship in my entity class. After deleting the attribute, so the model was consistent with the database, everything started to work fine. Strange that the environment does not produce a warning or exception of some kind.

Upvotes: 3

cdmckay
cdmckay

Reputation: 32290

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.

Upvotes: 12

Pascal Thivent
Pascal Thivent

Reputation: 570605

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.

Upvotes: 1

apiri
apiri

Reputation: 1633

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.

Upvotes: 0

Peter Krogh
Peter Krogh

Reputation: 362

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...

Upvotes: 3

bashflyng
bashflyng

Reputation: 911

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

Upvotes: 0

Related Questions