使用 Restkit 通过外键连接一对多

Connect one-to-many by foreign key using Restkit

我有这些型号:

extension Notification {

    @NSManaged var pk: NSNumber?
    @NSManaged var subtitle: String?
    @NSManaged var title: String?
    @NSManaged var user: User?

}

extension User {
    // here's some attributes
    @NSManaged var pk: NSNumber?
    @NSManaged var notifications: NSSet?
    // and here's really some more..
}

列出用户通知的响应可能如下所示:

[
    {
        "pk": 2,
        "title": "Hi mate",
        "subtitle": "O hoy",
        "user": 2
    }
]

"user": 2表示属于pk=2的用户。

如何正确地将此通知映射到用户?我的尝试是:

let mapping = RKEntityMapping(forEntityForName: String(Notification), inManagedObjectStore: RKObjectManager.sharedManager().managedObjectStore)

mapping.identificationAttributes = [ "pk" ]

mapping.addAttributeMappingsFromDictionary([
    "pk": "pk",
    "title": "title",
    "subtitle": "subtitle",
])

mapping.addConnectionForRelationship("user", connectedBy: [
  "user.pk": "pk"
])

我能做到

mapping.addConnectionForRelationship("user", connectedBy: [
  "pk"
])

但随后它将其连接到与 Notification.

具有相同 pk 的用户

我得到的错误是:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Cannot connect relationship: invalid attributes given for source entity 'Notification': user.pk'

我怎样才能做到这一点?

我是否被迫在通知中添加临时 属性 用户,然后将 userPk 映射到 pk?

编辑: 我现在已经使用瞬态属性让它工作了,这是唯一的方法吗?

mapping.identificationAttributes = [ "pk" ]

mapping.addAttributeMappingsFromDictionary([
  "pk": "pk",
  "title": "title",
  "subtitle": "subtitle",
  "user": "userPk"
])

mapping.addConnectionForRelationship("user", connectedBy: [
  "userPk": "pk"
])

userPk 现在是 Notification

上的 属性 瞬态

只要你只得到用户的ID,是的,你需要使用方法addConnectionForRelationship和一个瞬态属性。但是,如果您的后端将为您提供用户对象而不是 ID,您可以在 RKEntityMapping 上使用 addPropertyMapping 方法。然后我会建议一个类似于这样的模式:

import Foundation
import CoreData
import RestKit

protocol Mappable {
    static var entityName: String {get}
    static var identityAttribute: String? {get}
    static func mapping(managedObjectStore: RKManagedObjectStore) -> RKEntityMapping
    static func identificationAttributes() -> [String]?
    static func createPropertyMappings(managedObjectStore: RKManagedObjectStore, objectMapping: RKObjectMapping) -> [RKRelationshipMapping]?
    static func attributesDictionary() -> Dictionary<String, String>?
    static func requestDescriptor(managedObjectStore: RKManagedObjectStore) -> RKRequestDescriptor
}

class ManagedObject: NSManagedObject, Mappable {

    //MARK: - ManagedObjectProtocol Methods
    class func mapping(managedObjectStore: RKManagedObjectStore) -> RKEntityMapping {
        let mapping = RKEntityMapping(
            forEntityForName: entityName,
            inManagedObjectStore: managedObjectStore
        )

        if let identityAttribute = identityAttribute {
            mapping.identificationAttributes = [identityAttribute]
        }

        if let attributeMapping = attributes {
            mapping.addAttributeMappingsFromDictionary(attributeMapping)
        }

        if let propertyMappings = createPropertyMappings(managedObjectStore, objectMapping: mapping) {
            for propertyMapping in propertyMappings {
                mapping.addPropertyMapping(propertyMapping)
            }
        }

        return mapping
    }

    class var entityName: String { 
        fatalError("must override") 
    }

    class var identityAttribute: String? {
        //override me
        return nil
    }

    class func attributesDictionary() -> Dictionary<String, String>? {
        //override me
        return nil
    }

    class func createPropertyMappings(managedObjectStore: RKManagedObjectStore, objectMapping: RKObjectMapping) -> [RKRelationshipMapping]? {
        //override me if needed
        return nil
    }

    class func requestDescriptor(managedObjectStore: RKManagedObjectStore) -> RKRequestDescriptor {
        let inversedMapping = mapping(managedObjectStore).inverseMapping()
        let descriptor = RKRequestDescriptor(mapping: inversedMapping, objectClass: self, rootKeyPath: nil, method: RKRequestMethod.Any)
        return descriptor
    }

}

class Notification: ManagedObject {

    //MARK: - ManagedObjectProtocol Methods
    class var entityName: String {
        return "Notification"
    }

    override class func attributesDictionary() -> Dictionary<String, String>? {
        let dictionary = [
            "pk": "pk",
            "title": "title",
            "subtitle": "subtitle"
        ]
        return dictionary
    }

    override class func createPropertyMappings(managedObjectStore: RKManagedObjectStore, objectMapping: RKObjectMapping) -> [RKRelationshipMapping]? {
        let bookmarksPropertyMapping = RKRelationshipMapping(
            fromKeyPath: "user",
            toKeyPath: "user",
            withMapping: User.mapping(managedObjectStore)
        )

        return [bookmarksPropertyMapping]
    }
}

class User: ManagedObject {
    //MARK: - ManagedObjectProtocol Methods
    class var entityName: String {
        return "User"
    }

    override class func attributesDictionary() -> Dictionary<String, String>? {
        let dictionary = [
            "pk": "pk"
        ]
        return dictionary
    }
}