我遇到了JPA和Hibernate的问题,EntityManager.find()
甚至EntityManager.createQuery()
都不会在我的数据库中返回具有相应ID的实体。前者返回null
,后者抛出No entity found for query
异常。我知道具有该ID的实体存在于数据库中,因为我在运行代码时盯着该条目。
我需要采取一些步骤才能找到失败的地方。首先,我在我的DayItem表中添加两个项目并将它们返回给客户端。我在客户端上更改它们的值并使用POST将它们发送回服务器。一旦收到服务器,我就创建一个新的EntityManager
并尝试通过获取其类和ID并将这些值传递给EntityManager.find(Class, ID)
来按ID删除实体。
这将在数据库中查找具有原始值的实体,而不是从客户端发送的已更改实体。 EntityManager.find(Class, ID)
也正是问题发生的地方。找到数据库中的实体后,我会在实体上调用EntityManager.remove()
将其删除。
当服务器收到实体时,我没有直接在实体上使用EntityManager.merge()
的原因是因为它们的唯一密钥被交换了,这会导致约束违规,除非我从中删除它们运行EntityManager.merge()
之前的数据库。
最后,在删除数据库中的实体后,我会通过调用EntityManager.merge()
来更新它们的更新值。
请查看下面的代码,有关EntityManager.find()
返回null的原因的任何帮助以及查询引发No entity found for query
异常的原因将是一个很大的帮助。
这是DayItem表上的唯一键:
ALTER TABLE DAY_ITEM
ADD CONSTRAINT DAY_ITEM_UK
UNIQUE (EMAIL, MOD_ID, FM_ORDER, DAYS_DATE);
这是DayItem表实体:
@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;
}
}
这是添加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;
}
这是删除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;
}
}
}