Có phải mọi mối quan hệ dữ liệu cốt lõi đều phải có nghịch đảo?


150

Giả sử tôi có hai lớp Thực thể: SocialAppSocialAppType

Trong SocialApptôi có một Thuộc tính: appURLvà một Mối quan hệ : type.

Trong SocialAppTypetôi có ba thuộc tính: baseURL, namefavicon.

Đích đến của SocialAppmối quan hệ typelà một bản ghi trong SocialAppType.

Ví dụ: đối với nhiều tài khoản Flickr, sẽ có một số SocialAppbản ghi, với mỗi bản ghi giữ một liên kết đến tài khoản của một người. Sẽ có một SocialAppTypebản ghi cho loại "Flickr", tất cả các SocialAppbản ghi sẽ trỏ đến.

Khi tôi xây dựng một ứng dụng với lược đồ này, tôi nhận được một cảnh báo rằng không có mối quan hệ nghịch đảo giữa SocialAppTypeSocialApp.

 /Users/username/Developer/objc/TestApp/TestApp.xcdatamodel:SocialApp.type: warning: SocialApp.type -- relationship does not have an inverse

Tôi có cần một nghịch đảo, và tại sao?

Câu trả lời:


117

Trong thực tế, tôi không bị mất dữ liệu do không có nghịch đảo - ít nhất là tôi biết. Google nhanh chóng gợi ý bạn nên sử dụng chúng:

Một mối quan hệ nghịch đảo không chỉ khiến mọi thứ trở nên gọn gàng hơn, nó thực sự được Core Data sử dụng để duy trì tính toàn vẹn dữ liệu.

- Ca cao trung tâm

Thông thường bạn nên mô hình hóa các mối quan hệ theo cả hai hướng và chỉ định các mối quan hệ nghịch đảo một cách thích hợp. Dữ liệu cốt lõi sử dụng thông tin này để đảm bảo tính nhất quán của biểu đồ đối tượng nếu có thay đổi (xem Mối quan hệ thao tác và biểu đồ đối tượng toàn vẹn). Để thảo luận về một số lý do tại sao bạn có thể không muốn mô hình hóa mối quan hệ theo cả hai hướng và một số vấn đề có thể phát sinh nếu bạn không, hãy xem Mối quan hệ đơn hướng.

- Hướng dẫn lập trình dữ liệu cốt lõi


5
Xem câu trả lời của MadNik (ở cuối trang tại thời điểm tôi đang viết bài này) để được giải thích kỹ hơn về ý nghĩa của các tài liệu khi họ nói rằng các mối quan hệ nghịch đảo giúp duy trì tính toàn vẹn dữ liệu.
Đánh dấu Amery

135

Tài liệu của Apple có một ví dụ tuyệt vời cho thấy một tình huống mà bạn có thể gặp vấn đề bằng cách không có mối quan hệ nghịch đảo. Hãy ánh xạ nó vào trường hợp này.

Giả sử bạn mô hình hóa nó như sau: nhập mô tả hình ảnh ở đây

Lưu ý rằng bạn có mối quan hệ một-một gọi là " loại ", từ SocialAppđến SocialAppType. Mối quan hệ là không tùy chọn và có quy tắc xóa "từ chối" .

Bây giờ hãy xem xét những điều sau đây:

SocialApp *socialApp;
SocialAppType *appType;
// assume entity instances correctly instantiated

[socialApp setSocialAppType:appType];
[managedObjectContext deleteObject:appType];
BOOL saved = [managedObjectContext save:&error];

Những gì chúng tôi mong đợi là thất bại trong việc lưu bối cảnh này vì chúng tôi đã đặt quy tắc xóa là Từ chối trong khi mối quan hệ là không bắt buộc.

Nhưng ở đây tiết kiệm thành công.

Lý do là chúng tôi chưa thiết lập mối quan hệ nghịch đảo . Do đó, cá thể ứng dụng xã hội không được đánh dấu là đã thay đổi khi appType bị xóa. Vì vậy, không có xác nhận nào xảy ra cho SocialApp trước khi lưu (nó cho rằng không cần xác thực vì không có thay đổi nào xảy ra). Nhưng thực sự là một sự thay đổi đã xảy ra. Nhưng nó không được phản ánh.

Nếu chúng tôi nhớ lại appType bởi

SocialAppType *appType = [socialApp socialAppType];

Loại ứng dụng là không.

Thật lạ phải không? Chúng tôi nhận được không cho một thuộc tính không tùy chọn?

Vì vậy, bạn sẽ không gặp rắc rối nếu bạn đã thiết lập mối quan hệ nghịch đảo. Nếu không, bạn phải thực hiện xác nhận bằng cách viết mã như sau.

SocialApp *socialApp;
SocialAppType *appType;
// assume entity instances correctly instantiated

[socialApp setSocialAppType:appType];
[managedObjectContext deleteObject:appType];

[socialApp setValue:nil forKey:@"socialAppType"]
BOOL saved = [managedObjectContext save:&error];

9
Đây là một câu trả lời tuyệt vời; cảm ơn vì đã đánh vần chi tiết rõ ràng những gì - từ các tài liệu và từ tất cả những gì tôi đã đọc - lập luận chính ủng hộ việc đảo ngược mọi thứ, ngay cả khi mối quan hệ nghịch đảo không có ý nghĩa nhân văn. Điều này thực sự nên là câu trả lời được chấp nhận. Tất cả các chủ đề câu hỏi này hiện đang thiếu là một khám phá chi tiết hơn về các lý do bạn có thể chọn không có nghịch đảo, chạm vào câu trả lời của Rose Perrone (và cả trong tài liệu, một chút).
Mark Amery

46

Tôi sẽ diễn giải câu trả lời dứt khoát mà tôi tìm thấy trong Phát triển iPhone 3 khác của Dave Mark và Jeff LeMarche.

Apple thường khuyên bạn luôn luôn tạo và chỉ định nghịch đảo, ngay cả khi bạn không sử dụng mối quan hệ nghịch đảo trong ứng dụng của mình. Vì lý do này, nó cảnh báo bạn khi bạn không cung cấp ngược lại.

Mối quan hệ không bắt buộc phải có nghịch đảo, bởi vì có một vài tình huống trong đó mối quan hệ nghịch đảo có thể làm tổn hại đến hiệu suất. Ví dụ, giả sử mối quan hệ nghịch đảo chứa một số lượng cực lớn các đối tượng. Loại bỏ nghịch đảo yêu cầu lặp lại trên tập đại diện cho hiệu suất nghịch đảo, làm suy yếu.

Nhưng trừ khi bạn có một lý do cụ thể để không, mô hình hóa nghịch đảo . Nó giúp Core Data đảm bảo tính toàn vẹn dữ liệu. Nếu bạn gặp phải các vấn đề về hiệu suất, việc loại bỏ mối quan hệ nghịch đảo sau này là tương đối dễ dàng.


24

Câu hỏi tốt hơn là, "có lý do để không có nghịch đảo" không? Dữ liệu cốt lõi thực sự là một khung quản lý đồ thị đối tượng, không phải là khung bền vững. Nói cách khác, công việc của nó là quản lý các mối quan hệ giữa các đối tượng trong biểu đồ đối tượng. Mối quan hệ nghịch đảo làm cho điều này dễ dàng hơn nhiều . Vì lý do đó, Core Data mong đợi các mối quan hệ nghịch đảo và được viết cho trường hợp sử dụng đó. Không có chúng, bạn sẽ phải tự mình quản lý biểu đồ đối tượng. Cụ thể, nhiều mối quan hệ không có mối quan hệ nghịch đảo rất có thể bị hỏng bởi Core Data trừ khi bạn làm việc rất chăm chỉ để giữ mọi thứ hoạt động. Chi phí về kích thước đĩa cho các mối quan hệ nghịch đảo thực sự không đáng kể so với lợi ích mà nó mang lại cho bạn.


20

Có ít nhất một kịch bản trong đó một trường hợp tốt có thể được thực hiện cho mối quan hệ dữ liệu cốt lõi mà không có nghịch đảo: khi đã có một mối quan hệ dữ liệu cốt lõi khác giữa hai đối tượng, sẽ xử lý việc duy trì biểu đồ đối tượng.

Chẳng hạn, một cuốn sách chứa nhiều trang, trong khi một trang nằm trong một cuốn sách. Đây là mối quan hệ hai chiều một chiều. Xóa một trang chỉ vô hiệu hóa mối quan hệ, trong khi xóa một cuốn sách cũng sẽ xóa trang.

Tuy nhiên, bạn cũng có thể muốn theo dõi trang hiện tại đang được đọc cho mỗi cuốn sách. Điều này có thể được thực hiện với một "currentPage" bất động sản trên trang , nhưng sau đó bạn cần logic khác để đảm bảo rằng chỉ có một trang trong cuốn sách được đánh dấu là trang hiện bất cứ lúc nào. Thay vào đó, thực hiện mối quan hệ currentPage từ Sách sang một trang sẽ đảm bảo rằng sẽ luôn chỉ có một trang hiện tại được đánh dấu và hơn nữa trang này có thể được truy cập dễ dàng với tham chiếu đến sách chỉ bằng book.cienPage.

Trình bày đồ họa về mối quan hệ dữ liệu cốt lõi giữa sách và trang

Mối quan hệ qua lại trong trường hợp này là gì? Một cái gì đó phần lớn vô nghĩa. "MyBook" hoặc tương tự có thể được thêm lại theo hướng khác, nhưng nó chỉ chứa thông tin đã có trong mối quan hệ "sách" cho trang và do đó tạo ra rủi ro riêng. Có lẽ trong tương lai, cách bạn đang sử dụng một trong những mối quan hệ này đã thay đổi, dẫn đến thay đổi cấu hình dữ liệu cốt lõi của bạn. Nếu page.myBook đã được sử dụng ở một số nơi mà page.book nên được sử dụng trong mã, có thể có vấn đề. Một cách khác để chủ động tránh điều này cũng là không để lộ MyBook trong lớp con NSManagedObject được sử dụng để truy cập trang. Tuy nhiên, có thể lập luận rằng đơn giản hơn là không mô hình hóa nghịch đảo ở vị trí đầu tiên.

Trong ví dụ được nêu, quy tắc xóa cho mối quan hệ currentPage nên được đặt thành "Không hành động" hoặc "Xếp tầng", vì không có mối quan hệ qua lại với "Nullify". (Cascade ngụ ý rằng bạn đang xé mọi trang ra khỏi cuốn sách khi bạn đọc nó, nhưng điều đó có thể đúng nếu bạn đặc biệt lạnh và cần nhiên liệu.)

Khi có thể chứng minh rằng tính toàn vẹn của đồ thị đối tượng không có nguy cơ, như trong ví dụ này, độ phức tạp và khả năng bảo trì mã được cải thiện, có thể lập luận rằng một mối quan hệ không có nghịch đảo có thể là quyết định chính xác.


Cảm ơn Duncan - điều này cực kỳ gần với trường hợp sử dụng mà tôi có. Về cơ bản, tôi cần có thể có được trang cuối cùng của một cuốn sách. Tôi cần giá trị này là một giá trị bền vững để tôi có thể sử dụng nó trong một vị từ tìm nạp. Tôi đã thiết lập một nghịch đảo "bookIAmLastPageOf", nhưng nó khá vô lý và gây ra các vấn đề khác (tôi không hiểu đúng). Bạn có biết có cách nào để vô hiệu hóa cảnh báo cho một trường hợp không?
Stewohn

Có cách nào để vô hiệu hóa các cảnh báo? Bây giờ tôi có 2: ... nên có quy tắc xóa ngượckhông có hành động xóa ... có thể dẫn đến mối quan hệ với các đối tượng bị xóa . Và có thể currentPageđược đánh dấu là Optional?
SwiftArchitect

Việc lưu trữ currentPage dưới dạng NSManagedObjectID thay vì mối quan hệ có phải là một cách tiếp cận hợp lệ không?
dùng965972

4

Mặc dù các tài liệu dường như không yêu cầu nghịch đảo, tôi chỉ giải quyết một tình huống thực tế dẫn đến "mất dữ liệu" bằng cách không có nghịch đảo. Tôi có một đối tượng báo cáo có mối quan hệ nhiều đối tượng trên các đối tượng báo cáo. Không có mối quan hệ nghịch đảo, bất kỳ thay đổi nào đối với mối quan hệ nhiều người đã bị mất khi khởi chạy lại. Sau khi kiểm tra gỡ lỗi Core Data, rõ ràng là mặc dù tôi đang lưu đối tượng báo cáo, các cập nhật cho biểu đồ đối tượng (các mối quan hệ) không bao giờ được thực hiện. Tôi đã thêm một nghịch đảo, mặc dù tôi không sử dụng nó và voila, nó hoạt động. Vì vậy, nó có thể không nói là cần thiết nhưng các mối quan hệ không có nghịch đảo chắc chắn có thể có tác dụng phụ lạ.


0

Đảo ngược cũng được sử dụng cho Object Integrity(vì lý do khác, xem các câu trả lời khác):

Cách tiếp cận được đề xuất là mô hình hóa các mối quan hệ theo cả hai hướng và chỉ định các mối quan hệ nghịch đảo một cách thích hợp. Dữ liệu cốt lõi sử dụng thông tin này để đảm bảo tính nhất quán của biểu đồ đối tượng nếu thay đổi được thực hiện

Từ: https://developer.apple.com/lvern/archive/documentation/Cocoa/Conceptual/CoreData/HowManagedObjectsarerelated.html#//

Liên kết được cung cấp cho bạn ý tưởng tại sao bạn nên có một inversebộ. Không có nó, bạn có thể mất dữ liệu / tích hợp. Ngoài ra, cơ hội mà bạn truy cập vào một đối tượng có nilnhiều khả năng.


0

Không cần cho mối quan hệ nghịch đảo nói chung. Nhưng có một vài quirks / lỗi trong dữ liệu Core mà bạn cần có mối quan hệ nghịch đảo. Có những trường hợp mối quan hệ / đối tượng bị mất, mặc dù không có lỗi trong khi lưu bối cảnh, nếu thiếu mối quan hệ nghịch đảo. Kiểm tra ví dụ này , mà tôi đã tạo để chứng minh các đối tượng bị thiếu và cách khắc phục, trong khi làm việc với dữ liệu Core

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.