7

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;
    }
    ...
}
Pascal Thivent
  • 562,542
  • 136
  • 1,062
  • 1,124
cdmckay
  • 31,832
  • 25
  • 83
  • 114

6 Answers6

12

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
  • 31,832
  • 25
  • 83
  • 114
3

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.

Javasick
  • 2,753
  • 1
  • 23
  • 35
pkudlacik
  • 31
  • 2
3

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
  • 362
  • 2
  • 2
  • I should be flushing the EM prior to the find? I'm using Hibernate as my provider. – cdmckay Jul 08 '10 at 18:19
  • 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 Jul 08 '10 at 18:21
  • 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 Jul 08 '10 at 20:11
  • *"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 Jul 08 '10 at 21:00
1

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
  • 562,542
  • 136
  • 1,062
  • 1,124
0

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

bashflyng
  • 911
  • 1
  • 6
  • 5
0

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
  • 1,635
  • 9
  • 15
  • 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 Jul 08 '10 at 20:12