2016-07-03 19 views
0

EntityManager.merge()で非常に奇妙な動作が発生しています。ここで何が起こっているのですか?私は、MySQLデータベースから項目を挿入、更新、および削除するためのSpring MVC、Hibernate、およびJPAを備えたREST API設定を持っています。挿入機能と更新機能はどちらもEntityManager.merge()を使用し、両方とも99%の時間で正常に機能します。EntityManagerのmerge()によって重複行が発生する

ただし、最初にレコードを更新するように呼び出された時点では、データベースにレコードの複製が作成され、元のレコードに戻り、必要な変更が加えられます。

私は本当になぜこれが起こっているのか迷っています。重複したレコードを作成した場合、そのレコードを編集することはできますが、更新では重複を作成して放棄し、変更を加えるために最初のレコードに戻ります。

エンティティBeanにハッシュコードと等価な設定がどのようにあるのかが原因であると考えていました。私は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; 
    } 
} 
+0

エンティティは更新時にIDを持っていますか? –

+0

@DanielJipaはい、元のレコードと同じIDです。 – Graham

答えて

0

equalshasCode 、Hibernateはこれらのメソッドを使用してentiを検索します更新する予定です。切り離されたオブジェクトが変更されたと仮定すると、equalshasCodeは決して添付されたエンティティと同じ値を返さないので、Hibernateはそれが新しいインスタンスであるとみなします。

equals and hasCodeについての休止状態のドキュメントを読む必要があります。

+0

慎重にデバッグした後、私はこれが問題ではないと判断しました。更新関数が実行されるたびに、 'EntityManager.contains()'はそれを渡すエンティティに対してfalseを返します。つまり、永続コンテキストには存在しません。一度にfalseを返しますが、重複を1回しか作成しません。だから何か別のことが起こっている。 – Graham

+0

equalsとhashCodeの実装を変更してIdのみを使用する –

+0

@DanielJipa IDで検索するエンティティのクラスを取る 'EntityManager.find()'を使用しました。更新関数の呼び出しの1つでは、null値を返します。それはそれを見つけることができなかったことを意味する。しかし、どちらか一方の呼び出しでのみ。 DayItemの量フィールドが1.02に等しいとき、常に同じポイントになります。それは常に1.02で、他の数値はDayItemを複製しません。私は本当に迷っています。 – Graham

関連する問題