Я получаю очень странное поведение с EntityManager.merge()
. Вот что происходит. У меня есть настройка REST API с Spring MVC, Hibernate и JPA для вставки, обновления и удаления элементов из базы данных MySQL. Функции вставки и обновления используют EntityManager.merge()
, и оба они отлично работают в 99% случаев.EntityManager merge() вызывает повторяющиеся строки
Однако в какой-то момент, который, по-видимому, является первым вызовом для обновления записи, он создает дубликат записи в базе данных и затем возвращается к исходной записи и вносит в нее изменения, как следует.
Я действительно в недоумении, почему это происходит. Вы могли бы подумать, что если бы он создал дубликат записи, он отредактировал бы это, но нет, при обновлении он создаст дубликат, покинет его и вернется к первой записи, чтобы внести изменения.
Я думал, что это из-за того, что у меня есть мой хэш-код и равна настройке в моих сущностях, что это может быть. Хотя я не вижу в них ничего плохого, так как я основывал их на уникальных ключах, а не на ID.
Мой код ниже. Любые идеи о том, что происходит, будут большой помощью.
Вот сущность:
@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() {
if(daysDateString == null) {
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
return formatter.format(daysDate);
}
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;
if (!getDaysDateString().equals(dayItem.getDaysDateString())) return false;
if (getFoodId() != null ? !getFoodId().equals(dayItem.getFoodId()) : dayItem.getFoodId() != null) return false;
return getMealId() != null ? getMealId().equals(dayItem.getMealId()) : dayItem.getMealId() == null;
}
@Override
public int hashCode() {
int result = getEmail().hashCode();
result = 31 * result + getModId().hashCode();
result = 31 * result + getFmOrder().hashCode();
result = 31 * result + getDaysDateString().hashCode();
result = 31 * result + (getFoodId() != null ? getFoodId().hashCode() : 0);
result = 31 * result + (getMealId() != null ? getMealId().hashCode() : 0);
return result;
}
}
Вот код делает первоначальный создать:
@Override
public List<DayItem> saveDayItem(DayItem item) throws Exception {
EntityManager manager = entityManagerFactory.createEntityManager();
EntityTransaction tx = manager.getTransaction();
List<DayItem> results = null;
try {
tx.begin();
manager.merge(item);
manager.flush();
manager.clear();
results = findUserDay(item.getDaysDate(), item.getEmail(), manager);
tx.commit();
} catch (Exception e) {
tx.rollback();
throw e;
} finally {
manager.close();
return results;
}
}
Вот код делает обновление:
public <T extends GtEntity> T store(T entity) throws Exception {
T managedEntity = null;
EntityManager manager = entityManagerFactory.createEntityManager();
EntityTransaction tx = manager.getTransaction();
try{
tx.begin();
managedEntity = manager.merge(entity);
tx.commit();
}catch(RuntimeException e){
tx.rollback();
throw e;
}finally {
manager.close();
return managedEntity;
}
}
Имеет ли объект идентификатор при обновлении? –
@ DanielJipa Да, он имеет тот же идентификатор, что и оригинальная запись. – Graham