2009-04-18 36 views
132

Hãy nói rằng tôi có hai lớp Entity: SocialAppSocialAppTypeMọi mối quan hệ dữ liệu cốt lõi đều phải có một nghịch đảo?

Trong SocialApp tôi có một thuộc tính: appURL và một mối quan hệ: type.

Trong SocialAppType Tôi có ba Thuộc tính: baseURL, namefavicon.

Điểm đến của mối quan hệ SocialApptype là một bản ghi duy nhất trong SocialAppType.

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

Khi tôi tạo một ứng dụng với lược đồ này, tôi nhận được 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 nghịch đảo không và tại sao?

Trả lời

107

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. Mộ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ỉ làm cho mọi việc gọn gàng hơn, nó thực sự sử dụng bởi Core Data để duy trì dữ liệu liêm chính.

- Cocoa Dev Central

Bạn thường nên mô hình mối quan hệ trong cả hai hướng, và xác đị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 là được thực hiện (xem “Thao tác mối quan hệ và đối tượng đồ thị toàn vẹn”). Đối với một cuộc thảo luận của một số trong những lý do tại sao bạn có thể muốn không mô hình hóa một 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, xem “Unidirectional mối quan hệ.”

- Core Data Programming Guide

+5

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

21

câu hỏi tốt hơn là, "là có một lý do không để có một nghịch đảo"? 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à một khuôn khổ kiên trì. 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 đồ thị đối tượng. Các mối quan hệ nghịch đảo làm cho số này nhiều hơn dễ dàng hơn. 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 đó. Nếu không có chúng, bạn sẽ phải tự mình quản lý tính nhất quán của đồ thị đối tượng.Đặc biệt, 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 Dữ liệu cốt lõi trừ khi bạn làm việc rất khó để giữ cho 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ự là không đáng kể so với lợi ích mà nó mang lại cho bạn.

44

Tôi sẽ diễn giải câu trả lời cuối cùng tôi tìm thấy trong Phát triển iPhone 3 khác bởi Dave Mark và Jeff LeMarche.

Apple thường khuyên bạn nê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 một nghịch đảo.

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

Nhưng trừ khi bạn có lý do cụ thể không, mô hình 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, thì tương đối dễ dàng để loại bỏ mối quan hệ nghịch đảo sau này.

112

Tài liệu của Apple có một ví dụ tuyệt vời cho thấy tình huống mà bạn có thể gặp vấn đề khi 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 nó như sau: enter image description here

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

Bây giờ xem xét như sau:

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

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

gì chúng tôi mong đợi là thất bại bối cảnh này tiết kiệm vì chúng ta đã thiết lập các quy tắc xóa như Deny trong khi mối quan hệ là không bắt buộc.

Nhưng tại đây lưu thành công.

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

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

SocialAppType *appType = [socialApp socialAppType]; 

appType là con số không.

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

Vì vậy, bạn 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 thực 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]; 
+7

Đây là một câu trả lời tuyệt vời; cảm ơn cho chính tả rõ ràng những gì là - 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 có những nghịch đảo cho mọi thứ, ngay cả khi mối quan hệ nghịch đảo không có ý nghĩa con người. Điều này thực sự phải là câu trả lời được chấp nhận.Tất cả các chuỗi câu hỏi này bị thiếu bây giờ là một khám phá chi tiết hơn về lý do bạn có thể chọn * không * để có inverses, xúc động trong câu trả lời của Rose Perrone (và cũng trong tài liệu, một chút). –

17

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

Ví dụ: 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-một. 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 thuộc tính "currentPage" trên Trang, nhưng sau đó bạn cần logic khác để đảm bảo rằng chỉ một trang trong sách được đánh dấu là trang hiện tại bất kỳ lúc nào. Thay vào đó, hãy tạo mối quan hệ hiện tại từ Sách thành một trang sẽ đảm bảo rằng sẽ luôn có một trang đượ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ỉ với book.currentPage.

Graphical presentation of core data relationship between books and pages

Điều gì sẽ mối quan hệ đối ứng được trong trường hợp này? Một cái gì đó phần lớn vô nghĩa. "myBook" hoặc tương tự có thể được thêm trở lại theo một 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 các rủi ro của riêng nó. 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 được thay đổi, dẫn đến những thay đổi trong 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 phải đượ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 sẽ không hiển thị 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 là không mô hình nghịch đảo ở nơi đầu tiên.

Trong ví dụ được nêu, quy tắc xóa cho mối quan hệ hiện tại nên được đặt thành "Không có hành động" hoặc "Cascade", vì không có mối quan hệ đối ứng với "Nullify". (Cascade ngụ ý rằng bạn đang trích xuất 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 đồ thị đối tượng không có nguy cơ , như trong ví dụ này, và mã phức tạp và bảo trì được cải thiện, nó có thể được lập luận rằng một mối quan hệ mà không có một nghịch đảo có thể là quyết định chính xác.

+0

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ể nhận được ** trang cuối ** của một cuốn sách. Tôi cần điều 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 "bookIAmLastPageOf" nghịch đảo, nhưng nó khá vô nghĩa và đang gây ra các vấn đề khác (tôi không hiểu đúng). Bạn có biết nếu có một cách để vô hiệu hóa cảnh báo cho một trường hợp duy nhất? – Benjohn

+0

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

+0

Sẽ lưu trữ hiện tạiPage như một NSManagedObjectID thay vì một mối quan hệ là một cách tiếp cận hợp lệ? – user965972

4

Trong khi các tài liệu dường như không yêu cầu đảo ngược, tôi chỉ giải quyết một kịch bản thực tế dẫn đến "mất dữ liệu" do không có đảo ngược. Tôi có một đối tượng báo cáo có mối quan hệ nhiều với các đối tượng có thể báo cáo. Nếu 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 việc gỡ lỗi Core Data, rõ ràng là mặc dù tôi đã lưu đối tượng báo cáo, các bản cập nhật cho đồ thị đối tượng (các mối quan hệ) chưa bao giờ được thực hiện. Tôi thêm vào một nghịch đảo, mặc dù tôi không sử dụng nó, và thì đấy, nó hoạt động. Vì vậy, nó có thể không nói nó là cần thiết nhưng mối quan hệ mà không có inverses chắc chắn có thể có tác dụng phụ lạ.

Các vấn đề liên quan