2017-02-17 6 views
2

고유 한 제약 조건이있는 값을 교환해야합니다. 아래에 표시된대로 update_all 함수를 사용하려고합니다.고유 한 구속 조건을 가진 값을 Ecto로 바꾸는 올바른 방법은 무엇입니까?

from(e in Episode, where: e.show_id == ^id, update: [set: [position: fragment("position + 1")]]) 
|> Repo.update_all([]) 

이를 사용하여 I 때문에 중복 위치의 오류를 얻을 :

ERROR (unique_violation): duplicate key value violates unique constraint "position_show_id_index" 
table: episodes 
constraint: position_show_id_index 
Key ("position", show_id)=(2, 27) already exists. 

어떻게 동시에 이러한 위치 값을 바꿀 수 있습니까?

+1

나는 한 가지 방법은 트랜잭션을 사용하여 먼저 이전 레코드를 확인하고 삭제 한 다음 새 레코드를 삽입하는 것이라고 생각합니다. – JustMichael

답변

1

일반적으로 SQL의 고유 인덱스 값을 스왑하는 "좋은"방법은 없습니다.

Two known solutions는 양자를 업데이트하기 전에 다른 placholder 값 행을 업데이트 1) 삭제 및 재 삽입 행 또는 2)이다.

이 같은 체외에서 유사한 접근 방식을 취할 수 :

해결 방법 1 :

episode = Repo.get(Episode, id) 
next_episode = Repo.get_by(Episode, position: episode.position + 1) 

if next_episode, do: Repo.delete(next_episode) 

episode 
|> Episode.changeset(%{position: episode.position + 1}) 
|> Repo.update() 

if next_episode do 
    Repo.insert(%Episode{next_episode | position: episode.position}) 
end 

해결 방법 2 : (당신은 몇 가지 "불가능"값을 선택해야합니다 자리 표시 자입니다. 예를 들어 위치가 양수 여야하는 경우 음수를 사용할 수 있습니다.)

episode = Repo.get(Episode, id) 
next_episode = Repo.get_by(Episode, position: episode.position + 1) 

if next_episode do 
    next_episode 
    |> Episode.changeset(%{position: -1}) 
    |> Repo.update() 
end 

episode 
|> Episode.changeset(%{position: episode.position + 1}) 
|> Repo.update() 

if next_episode do 
    next_episode 
    |> Episode.changeset(%{position: episode.position}) 
    |> Repo.update() 
end 

Episode을 참조하는 외래 키 제약 조건이있는 경우 두 번째 솔루션이 더 좋을 수 있습니다.