2017-10-23 4 views
1

불필요한 쿼리를 트리거하지 않고 레일스의 has_many 연관에서 레코드를 제거하는 데 문제가 있습니다. 본질적으로, 나는 has_many 릴레이션이있는 모델을 가지고 있으며, 몇 가지 기준에 따라 여러 레코드를 제거하려고합니다. 나는 협회를 최신 상태로 유지하면서 동시에 데이터베이스에서 레코드를 제거 할 수 있기를 원하며 이렇게하기 위해 하나의 DELETE 쿼리 만 필요합니다. 나는 불필요한 UPDATE 쿼리를 생성하는 새로운 객체와의 관계를 할당하고 delete_all (하나의 쿼리를 만들지 만 연관을 업데이트하지 않음)을 호출하려고 시도했다.has_many에서 레코드 제거 단일 쿼리로 레일스 연결

+0

을 after_' 파괴). 미끄러운 슬로프 인 그 프로세스를 건너 뛰고 싶다면 "관련된 모든 객체 삭제"에 대한 모든 논리를 담고있는 서비스 객체를 생성하고 연관을 재설정하고 싶을 수도 있습니다. – MrYoshiji

+0

연관을 재설정하는 것이 최적이 아니라고 생각합니다. 나중에 연결에 액세스하면 관계에 있어야하는 내용을 알 수 있더라도 개체를 다시 가져와야하기 때문입니다. – mp94

+0

IMO를 사용하면 SQL 쿼리를 줄이고 Rails의 동작을 재정의해서는 안됩니다. 첫눈에 보이지는 않지만 여러 가지 문제로 이어질 수 있지만 나중에 전체 앱이 몇 달 동안 앱을 사용했을 때 ... – MrYoshiji

답변

0

관계에서 레코드를 삭제하는 두 가지 방법이 있습니다. destroy은 모든 관련 레코드를 한 번에 하나씩 삭제하고 삭제 된 각 레코드에서 콜백을 실행합니다. delete_all은 하나의 쿼리에서 모든 레코드를 삭제하고 콜백을 실행하지 않습니다.

그래서, 모델에 당신은 할 수 : 당신이 고객에게

pry(main) foo = Customer.first 
pry(main)> foo.destroy 
    (0.3ms) BEGIN 
    SQL (290.4ms) DELETE FROM `statements` WHERE `statements`.`customer_id` = 3 
    SQL (2.6ms) DELETE FROM `customers` WHERE `customers`.`id` = 3 

모든 하나의 팽창의 foop에서 수행을 삭제할 때

class Customer < ApplicationRecord 
    has_many :statements, dependent: :delete_all 

을하고, 아무런 콜백은 삭제합니다.

또는 - 각 의존 기록은 한 번에 하나씩 삭제 고객

pry(main) foo = Customer.first 
pry(main)> foo.destroy 
    (0.4ms) BEGIN 
    Statement Load (25.0ms) SELECT `statements`.* FROM `statements` WHERE `statements`.`customer_id` = 4 
    SQL (0.5ms) DELETE FROM `statements` WHERE `statements`.`id` = 9023 
    SQL (0.3ms) DELETE FROM `statements` WHERE `statements`.`id` = 9024 
    SQL (0.3ms) DELETE FROM `statements` WHERE `statements`.`id` = 9025 
    . . . etc etc etc . . . 

을 삭제할 때

class Customer < ApplicationRecord 
    has_many :statements, dependent: :destroy 

은하고, 콜백이 삭제 각에서 실행됩니다.

delete_alldestroy은 유사한 효과를 가진 결과 세트에서 실행할 수 있습니다. 그래서 당신은 관련 기록에 대한 몇 가지 필터가 원한다면 :

pry(main) foo = Customer.first 
pry(main)> bar = foo.statements.where(some_param: 42) 
pry(main)> bar.delete_all 
    SQL (4.2ms) DELETE FROM `statements` WHERE `statements`.`customer_id` = 7 AND `notices`.`some_param` = 42 
=> 2 

또는 - 레일은 각 당신이 콜백에게 (`before_`과`실행하기 위해 삭제할 개체를 찾을 필요가

pry(main) foo = Customer.first 
pry(main)> bar = foo.statements.where(some_param: 42) 
pry(main)> bar.destroy_all 
    (0.2ms) BEGIN 
    SQL (0.6ms) DELETE FROM `notices` WHERE `notices`.`id` = 4639 
    (0.5ms) COMMIT 
    (0.2ms) BEGIN 
    SQL (0.5ms) DELETE FROM `notices` WHERE `notices`.`id` = 4640 
    (0.4ms) COMMIT 
    (0.1ms) BEGIN 
    SQL (0.5ms) DELETE FROM `notices` WHERE `notices`.`id` = 4641 
    (0.5ms) COMMIT 
    . . . etc etc etc . . . 
+0

'foo.statements.where (some_param : 42) .delete_all'과 같은 것을하면 문제가됩니다. ,'foo.statements'는 더 이상 DB에 실제로 존재하지 않습니다. – mp94

+0

그런 경우, reload 명령문 :'foo.statements.reload' – rbb