查了一下,結果這是 MySQL 特有的問題。說是不能夠在變更資料時 select 同一個 table……
舉例來說,「將使用者 m 底下所有專案(Project)的『最後一個排程(Schedule)』刪除」。
以 HQL 來寫的話:
UPDATE Schedule s SET s.status = :Delete WHERE s IN ( SELECT MAX(s2) FROM Project p LEFT JOIN p.schedules as s2 LEFT JOIN p.manager as m WHERE m.id = :ID AND s2 = ( SELECT MAX(schedules) FROM Project WHERE id = p.id ) )
以SQL來寫的話:
UPDATE Schedule s SET s.status = :Delete WHERE s.id IN( SELECT s2.id FROM Project p LEFT JOIN Schedule s2 ON s2.project_id = p.id LEFT JOIN User m ON p.manager_id = m.id WHERE m.id = :ID AND s2.id = ( SELECT MAX(id) FROM Schedule WHERE project_id = p.id ) )
像這樣就會出現錯誤訊息:
You can't specify target table 'Schedule' for update in FROM clause
根據Stack Overflow的討論,看來是「insert」、「update」、「delete」都會遇到這種 BUG。
回到剛才的例子,若是要「將使用者 m 底下所有專案(Project)的『最後一個排程(Schedule)』刪除」,若是使用 Hibernate,最簡單的辦法就是先取得要刪除的 Schedule list ,如下所示:
org.hibernate.Session session; List<Schedule> schedules = session.createQuery("SELECT MAX(s) FROM Project p" + "LEFT JOIN Schedule s ON p.schedule_id = s.id " + "LEFT JOIN User m ON p.manager_id = m.id " + "WHERE m.id = :ID") .setParameter("ID", 1234567890) .list(); session.createQuery("UPDATE Schedule s " + "SET s.status = :Delete " + "WHERE s IN :List") .setParameter("Delete", "DELETE") .setParameterList("List", schedules) .executeUpdate(); // 關閉 session
在「博客园」中,有個人提出一種比較複雜的解法,他的方法是將變成子集,然後 update。算是個挺麻煩又複雜的解法。有興趣可以點超連結自行觀看
沒有留言:
張貼留言