0

I'm having a problem with JPA and Hibernate where EntityManager.find() or even EntityManager.createQuery() will not return an entity in my database with the corresponding ID. The former returns null and the latter throws a No entity found for query exception. I know for a fact that the entity with that ID exists in the database because I'm staring at the entry as the code is run.

There are a few steps I take to get to where it fails. First, I add two items to my DayItem table and return them to the client. I change their values on the client and use a POST to send them back to the server. Once received by the server I create a new EntityManager and attempt to delete the entities by ID by getting their class and ID and passing these values to EntityManager.find(Class, ID).

This finds the entity in the database with its original values, not the changed ones sent over from the client. EntityManager.find(Class, ID) is also exactly where the problem is happening. Once the entity from the database is found, I call EntityManager.remove() on the entity to remove it.

The reason that I don't use EntityManager.merge() directly on the entities right when they are received by the server is because their unique keys were swapped, and this would cause a constraint violation unless I delete them from the database before running EntityManager.merge().

Finally, after the entities from the database are removed, I add them back with their updated values by calling EntityManager.merge() on them.

Please take a look at my code below, any help with why EntityManager.find() returns null and why the query throws the No entity found for query exception would be a big help.

Here is the unique key on the DayItem table:

ALTER TABLE DAY_ITEM
ADD CONSTRAINT DAY_ITEM_UK
UNIQUE (EMAIL, MOD_ID, FM_ORDER, DAYS_DATE);

Here is the DayItem table entity:

@Entity
@Table(name = "DAY_ITEM")
public class DayItem implements GtEntity, Serializable{
    private Long id;
    private String email;
    private String name;
    private BigDecimal amount;
    private Integer modId;
    private Integer fmOrder;
    private String modName;
    private Date daysDate;
    private String daysDateString;
    private Long foodId;
    private Long mealId;
    private FoodItem foodItem;
    private MealItem mealItem;
    private ArrayList<FoodItem> foodItems;
    private ArrayList<MealItem> mealItems;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long getId() {
        return id;
    }

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

    @Basic
    @Column(name = "EMAIL", nullable = false, length = 50)
    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Basic
    @Column(name = "NAME", nullable = true, length = 100)
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Basic
    @Column(name = "AMOUNT", nullable = true)
    public BigDecimal getAmount() {
        return amount;
    }

    public void setAmount(BigDecimal amount) {
        this.amount = amount;
    }

    @Basic
    @Column(name = "MOD_ID", nullable = false)
    public Integer getModId() {
        return modId;
    }

    public void setModId(Integer modId) {
        this.modId = modId;
    }

    @Basic
    @Column(name = "FM_ORDER", nullable = false)
    public Integer getFmOrder() {
        return fmOrder;
    }

    public void setFmOrder(Integer fmOrder) {
        this.fmOrder = fmOrder;
    }

    @Basic
    @Column(name = "MOD_NAME", nullable = true, length = 50)
    public String getModName() {
        return modName;
    }

    public void setModName(String modName) {
        this.modName = modName;
    }

    @Basic
    @Column(name = "DAYS_DATE", nullable = false)
    public Date getDaysDate() {
        return daysDate;
    }

    public void setDaysDate(Date daysDate) {
        this.daysDate = daysDate;
    }

    @Transient
    public String getDaysDateString() {
        return daysDateString;
    }

    public void setDaysDateString(String daysDateString) {
        this.daysDateString = daysDateString;
    }

    @Basic
    @Column(name = "FOOD_ID", nullable = true)
    public Long getFoodId() {
        return foodId;
    }

    public void setFoodId(Long foodId) {
        this.foodId = foodId;
    }

    @Basic
    @Column(name = "MEAL_ID", nullable = true)
    public Long getMealId() {
        return mealId;
    }

    public void setMealId(Long mealId) {
        this.mealId = mealId;
    }

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "FOOD_ID", referencedColumnName = "ID",
            updatable = false, insertable = false)
    public FoodItem getFoodItem() {
        return foodItem;
    }

    public void setFoodItem(FoodItem foodItem) {
        this.foodItem = foodItem;
    }

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "MEAL_ID", referencedColumnName = "ID",
            updatable = false, insertable = false)
    public MealItem getMealItem() {
        return mealItem;
    }

    public void setMealItem(MealItem mealItem) {
        this.mealItem = mealItem;
    }

    @Transient
    public ArrayList<FoodItem> getFoodItems() {
        return foodItems;
    }

    public void setFoodItems(ArrayList<FoodItem> foodItems) {
        this.foodItems = foodItems;
    }

    @Transient
    public ArrayList<MealItem> getMealItems() {
        return mealItems;
    }

    public void setMealItems(ArrayList<MealItem> mealItems) {
        this.mealItems = mealItems;
    }

    public void makeDaysDate() throws ParseException{
        DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        this.daysDate = new Date(formatter.parse(this.daysDateString).getTime());
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof DayItem)) return false;

        DayItem dayItem = (DayItem) o;

        if (!getEmail().equals(dayItem.getEmail())) return false;
        if (!getModId().equals(dayItem.getModId())) return false;
        if (!getFmOrder().equals(dayItem.getFmOrder())) return false;
        return getDaysDate().equals(dayItem.getDaysDate());

    }

    @Override
    public int hashCode() {
        int result = getEmail().hashCode();
        result = 31 * result + getModId().hashCode();
        result = 31 * result + getFmOrder().hashCode();
        result = 31 * result + getDaysDate().hashCode();
        return result;
    }
}

Here's the code that adds a DayItem:

@Override
public List<DayItem> saveDayItem(DayItem item) throws Exception {
    List<DayItem> results = null;
    EntityManager manager = createEntityManager();
    EntityTransaction tx = manager.getTransaction();
    try {
        tx.begin();
        DayItem managedItem = manager.merge(item);
        manager.flush();
        manager.clear();
        tx.commit();
        results = findUserDay(managedItem.getDaysDate(), managedItem.getEmail(), manager);
    } catch (RuntimeException e) {
        tx.rollback();
        throw e;
    } finally {
        manager.close();
    }
    return results;
}

Here's the code that deletes the DayItems:

public <T extends GtEntity> void batchDelete(List<T> entities) throws Exception {
    if (!entities.isEmpty()) {
        EntityManager manager = createEntityManager();
        EntityTransaction tx = manager.getTransaction();
        try {
            tx.begin();
            for (int i = 0; i < entities.size(); i++) {
                if (i % this.jdbcBatchSize == 0) {
                    manager.flush();
                    manager.clear();
                }

                T del = entities.get(i);
                T managed = manager.find((Class<T>)del.getClass(), del.getId());
                //The line above is where the problem happens

                manager.remove(managed);
            }
            manager.flush();
            manager.clear();
            tx.commit();
        } catch (RuntimeException e) {
            tx.rollback();
            throw e;
        }
    }
}
Graham
  • 5,488
  • 13
  • 57
  • 92
  • Why does find() return null? maybe you'll find the answer when you look at the SQL invoked? and look at what is in the database. Maybe the object is not yet flushed? or tx isolation means it isn't seen – Neil Stockton Jul 08 '16 at 06:13
  • @NeilStockton Thank you for that comment. It was the tx isolation. In my hibernate config file I added `hibernate.connection.isolation=1`. Which sets the transaction isolation at `TRANSACTION_READ_UNCOMMITTED`. Which seems to have fixed it. With that I don't think I'll need all these flushes and clears anymore either. – Graham Jul 08 '16 at 06:50
  • you'll still need flush() because that will then send the data to the database ... the isolation simply means that your query can see the newly added data now. – Neil Stockton Jul 08 '16 at 06:55
  • @NeilStockton I set my `EntityManager` to `FlushMode.COMMIT` so it should be flushing after every transaction. I am noticing an issue now where Id's are getting mixed up so I'll look into adding back flush and clear as possible solutions. – Graham Jul 08 '16 at 07:30

3 Answers3

0
    public Clan saveClan(String ime, String prezime, String adresa, Date datumRodjenja, Date datumUpisa,
                int idKategorije) {
            try {
                EntityManager em = JPAUtil.getEntityManager();
                em.getTransaction().begin();
    
                Kategorija k = em.find(Kategorija.class, idKategorije);
                Clan c = new Clan();
                c.setIme(ime);
                c.setPrezime(prezime);
                c.setAdresa(adresa);
                c.setDatumRodjenja(datumRodjenja);
                c.setDatumUpisa(datumUpisa);
                c.setKategorija(k);
                em.persist(c);
    
                em.getTransaction().commit();
                return c;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }

public boolean razduzi(int id) {
        try {
            EntityManager em = JPAUtil.getEntityManager();
            em.getTransaction().begin();

            Zaduzenje z = em.find(Zaduzenje.class, id);
            z.setDatumVracanja(new Date());
            em.merge(z);

            em.getTransaction().commit();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
Dylan Dog
  • 1
  • 1
  • 1
    Thank you for this code snippet, which might provide some limited, immediate help. A [proper explanation](https://meta.stackexchange.com/q/114762/349538) would greatly improve its long-term value by showing why this is a good solution to the problem and would make it more useful to future readers with other, similar questions. Please [edit] your answer to add some explanation, including the assumptions you’ve made. – Muhammad Mohsin Khan Apr 04 '22 at 12:25
0
    public boolean deleteClan(Integer clBroj) {
            try {
                EntityManager em = JPAUtil.getEntityManager();
                em.getTransaction().begin();
    
                Clan c = em.find(Clan.class, clBroj);
    
                List<Zaduzenje> zaduzenjaClana = em
                        .createQuery("" + "select z from Zaduzenje z where " + "z.clan.clanskibroj=:br", Zaduzenje.class)
                        .setParameter("br", clBroj).getResultList();
    
                for (Zaduzenje z : zaduzenjaClana) {
                    em.remove(z);
                }
                em.remove(c);
                em.getTransaction().commit();
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }

public List<Integer> dodajPrimerke(int idKnjige, int brojPrimeraka) {
        ArrayList<Integer> invBrojevi = new ArrayList<Integer>();
        try {
            EntityManager em = JPAUtil.getEntityManager();
            Knjiga k = em.find(Knjiga.class, idKnjige);
            if (k != null) {
                em.getTransaction().begin();
                for (int i = 0; i < brojPrimeraka; i++) {
                    Primerak p = new Primerak();
                    p.setKnjiga(k);
                    em.persist(p);
                    invBrojevi.add(p.getInvBroj());
                }
                em.getTransaction().commit();
            }
            return invBrojevi;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
Dylan Dog
  • 1
  • 1
  • Thank you for this code snippet, which might provide some limited, immediate help. A [proper explanation](https://meta.stackexchange.com/q/114762/349538) would greatly improve its long-term value by showing why this is a good solution to the problem and would make it more useful to future readers with other, similar questions. Please [edit] your answer to add some explanation, including the assumptions you’ve made. – Muhammad Mohsin Khan Apr 04 '22 at 12:24
-1

public List getUlogeZaPredstavu(int idPredstave){ EntityManager em = JPAUtil.getEntityManager();

    List<Glumi> uloge = em.createQuery("select g from Glumi g where "
            + "g.uloga.predstava.idPredstava = :paramIdPredstava", Glumi.class)
            .setParameter("paramIdPredstava", idPredstave).getResultList();
    return uloge;
}

public Zanr getZanr(int id) {
    EntityManager em = JPAUtil.getEntityManager();
    Zanr z = em.find(Zanr.class, id);
    return z;
}
Dylan Dog
  • 1
  • 1