Sự khác biệt giữa Hủy và Xóa


210

Sự khác biệt giữa

@model.destroy@model.delete

Ví dụ:

Model.find_by(col: "foo").destroy_all
//and
Model.find_by(col: "foo").delete_all

Có thực sự quan trọng nếu tôi sử dụng cái này hay cái khác?

Câu trả lời:


289

Về cơ bản destroychạy bất kỳ cuộc gọi lại trên mô hình trong khi deletekhông.

Từ API Rails :

  • ActiveRecord::Persistence.delete

    Xóa bản ghi trong cơ sở dữ liệu và đóng băng trường hợp này để phản ánh rằng không nên thực hiện thay đổi nào (vì chúng không thể được duy trì). Trả về ví dụ đóng băng.

    Hàng được xóa đơn giản bằng câu lệnh XÓA SQL trên khóa chính của bản ghi và không có cuộc gọi lại nào được thực thi.

    Để thực thi các cuộc gọi lại before_destroy và after_destroy của đối tượng hoặc bất kỳ: tùy chọn liên kết phụ thuộc, hãy sử dụng #destroy.

  • ActiveRecord::Persistence.destroy

    Xóa bản ghi trong cơ sở dữ liệu và đóng băng trường hợp này để phản ánh rằng không nên thực hiện thay đổi nào (vì chúng không thể được duy trì).

    Có một loạt các cuộc gọi lại liên quan đến phá hủy. Nếu cuộc gọi lại before_destroy trả về false, hành động bị hủy và hủy trả về false. Xem ActiveRecord :: Callbacks để biết thêm chi tiết.


Xin chào @ user740584 - cảm ơn câu trả lời của bạn. Bạn có ý nghĩa gì khi "chạy bất kỳ cuộc gọi lại nào trên mô hình"?
BKSpurgeon

3
@BKSpurgeon có nghĩa là ActiveRecord :: Callbacks: api.rubyonrails.org/groupes/ActiveRecord/Callbacks.html . Một cuộc gọi lại như vậy model#before_destroycó thể được sử dụng để tạm dừng destroy()cuộc gọi cuối cùng trong những điều kiện nhất định.
Todd

102

delete sẽ chỉ xóa bản ghi đối tượng hiện tại khỏi db chứ không xóa các bản ghi con liên quan của nó khỏi db.

destroy sẽ xóa bản ghi đối tượng hiện tại khỏi db và bản ghi con liên quan của nó khỏi db.

Việc sử dụng chúng thực sự quan trọng:

Nếu nhiều đối tượng cha mẹ của bạn chia sẻ các đối tượng con chung, thì việc gọi destroyđối tượng cha cụ thể sẽ xóa các đối tượng con được chia sẻ giữa nhiều cha mẹ khác.


5
Rực rỡ trả lời. cảm ơn bạn. tôi sẽ nói thêm rằng thuật ngữ này vì tôi hiểu rằng trẻ em bị "giết". vô cùng tàn bạo.
BKSpurgeon

Trong hầu hết các trường hợp trong sản xuất, bạn muốn sử dụng 'hủy'
Bên ngoài_Box

Không, điều này là không cần thiết.
Taimoor Changaiz

Tôi nghĩ rằng từ bạn nên sử dụng destroycon cháu , không phải trẻ em : theo tài liệu, hủy "tạo một đối tượng mới từ các thuộc tính, và sau đó gọi hủy trên đó." rubydoc.info/docs/rails/4.1.7/ActiveRecord%2FRelation:destroy
Marco Lackovic

12

Khi bạn gọi destroyhoặc destroy_alltrên một ActiveRecordđối tượng,ActiveRecord quy trình 'hủy diệt' được bắt đầu, nó sẽ phân tích lớp bạn đang xóa, nó xác định những gì cần làm cho các phụ thuộc, chạy qua xác nhận, v.v.

Khi bạn gọi deletehoặc delete_alltrên một đối tượng, ActiveRecordchỉ cố gắng chạy DELETE FROM tablename WHERE conditionstruy vấn đối với db, không thực hiện các ActiveRecordtác vụ khác.


4

Có, có một sự khác biệt lớn giữa hai phương thức Sử dụng xóa_all nếu bạn muốn các bản ghi bị xóa nhanh chóng mà không cần gọi lại mô hình

Nếu bạn quan tâm đến các cuộc gọi lại mô hình của mình thì hãy sử dụng kill_all

Từ các tài liệu chính thức

http://apidock.com/rails/ActiveRecord/Base/destroy_all/ class

hủy_all (điều kiện = nil) công khai

Phá hủy các bản ghi khớp với các điều kiện bằng cách khởi tạo từng bản ghi và gọi phương thức hủy của nó. Các cuộc gọi lại của mỗi đối tượng được thực thi (bao gồm: các tùy chọn liên kết phụ thuộc và các phương thức Observer before_destroy / after_destroy). Trả về bộ sưu tập các đối tượng đã bị phá hủy; mỗi cái sẽ bị đóng băng, để phản ánh rằng không nên thay đổi (vì chúng không thể tồn tại).

Lưu ý: Khởi tạo, thực hiện gọi lại và xóa từng bản ghi có thể tốn thời gian khi bạn xóa nhiều bản ghi cùng một lúc. Nó tạo ra ít nhất một truy vấn XÓA SQL trên mỗi bản ghi (hoặc có thể hơn, để thực thi các cuộc gọi lại của bạn). Nếu bạn muốn xóa nhiều hàng một cách nhanh chóng, không cần quan tâm đến các liên kết hoặc cuộc gọi lại của chúng, thay vào đó hãy sử dụng xóa_all.


2

Về cơ bản "xóa" sẽ gửi một truy vấn trực tiếp đến cơ sở dữ liệu để xóa bản ghi. Trong trường hợp đó, Rails không biết thuộc tính nào trong bản ghi mà nó đang xóa cũng như nếu có bất kỳ cuộc gọi lại nào (chẳng hạn như before_destroy).

Phương thức "hủy" lấy id đã qua, tìm nạp mô hình từ cơ sở dữ liệu bằng phương thức "find", sau đó gọi hủy trên đó. Điều này có nghĩa là các cuộc gọi lại được kích hoạt.

Bạn sẽ muốn sử dụng "xóa" nếu bạn không muốn các cuộc gọi lại được kích hoạt hoặc bạn muốn hiệu suất tốt hơn. Nếu không (và hầu hết thời gian), bạn sẽ muốn sử dụng "hủy".


2

Rất nhiều câu trả lời rồi; muốn nhảy vào với một chút nữa.

tài liệu :

Đối với has_many, hủy và hủy_all sẽ luôn gọi phương thức hủy của (các) bản ghi bị xóa để các cuộc gọi lại được chạy. Tuy nhiên, xóa và xóa_all sẽ thực hiện xóa theo chiến lược được chỉ định bởi tùy chọn: phụ thuộc hoặc nếu không: tùy chọn phụ thuộc được đưa ra, thì nó sẽ tuân theo chiến lược mặc định. Chiến lược mặc định là không làm gì cả (để lại các khóa ngoại với bộ id gốc), ngoại trừ has_many: thông qua, trong đó chiến lược mặc định là xóa_all (xóa các bản ghi tham gia, mà không chạy các cuộc gọi lại của chúng).

Các deleteverbage hoạt động khác nhau cho ActiveRecord::Association.has_manyActiveRecord::Base. Đối với cái sau, xóa sẽ thực thi SQL DELETEvà bỏ qua tất cả các xác nhận / gọi lại. Cái trước sẽ được thực hiện dựa trên :dependenttùy chọn được truyền vào hiệp hội. Tuy nhiên, trong quá trình thử nghiệm, tôi đã tìm thấy tác dụng phụ sau đây trong đó các cuộc gọi lại chỉ được chạy deletevà khôngdelete_all

dependent: :destroy Thí dụ:

class Parent < ApplicationRecord
   has_many :children,
     before_remove: -> (_) { puts "before_remove callback" },
     dependent: :destroy
end

class Child < ApplicationRecord
   belongs_to :parent

   before_destroy -> { puts "before_destroy callback" }
end

> child.delete                            # Ran without callbacks
Child Destroy (99.6ms)  DELETE FROM "children" WHERE "children"."id" = $1  [["id", 21]]

> parent.children.delete(other_child)     # Ran with callbacks
before_remove callback
before_destroy callback
Child Destroy (0.4ms)  DELETE FROM "children" WHERE "children"."id" = $1  [["id", 22]]

> parent.children.delete_all              # Ran without callbacks
Child Destroy (1.0ms)  DELETE FROM "children" WHERE "children"."parent_id" = $1  [["parent_id", 1]]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.