2013-09-21 19 views
8

Ho problemi a mappare le relazioni quando la risposta JSON contiene solo la chiave primaria e non una matrice completamente nidificata per creare il nuovo oggetto.Mapping relazioni RestKit con chiave primaria

Ho 2 classi - Negozio e oggetto, e come ci si aspetterebbe che l'articolo Shop-> Item abbia una relazione uno-a-molti.

Ho un archivio locale di dati di base di negozi (e articoli), ciascuno con una chiave primaria. Vorrei quindi scaricare un elenco di elementi come JSON e mappare a entità di dati di base, ma includere solo la chiave primaria del negozio, e non tutti i dettagli del negozio come un array annidato - questo sarebbe un enorme spreco di traffico di rete mentre Sto scaricando i dettagli di oltre 500 articoli.

Ecco la JSON dai due richieste:

/negozi

{ 
    "id" : 1, 
    "shop" : "Shop A", 
    "city" : "New York" 
}, 
{ 
    "id" : 2, 
    "shop" : "Shop B", 
    "city" : "London" 
}, 
... 

/articoli

{ 
    "id" : 1, 
    "name" : "Shoes", 
    "manufacturer" : "Vans", 
    "shopId" : 1 
}, 
{ 
    "id" : 2, 
    "name" : "T-shirt", 
    "manufacturer" : "Animal", 
    "shopId" : 2 
}, 
{ 
    "id" : 3, 
    "name" : "Scarf", 
    "manufacturer" : "Ted Baker", 
    "shopId" : 1 
}, 
{ 
    "id" : 4, 
    "name" : "Sunglasses", 
    "manufacturer" : "Ray-Ban", 
    "shopId" : 3 
}, 
... 

Ecco il mio codice in questo momento .

AppDelegate.m

... 

NSURL *baseURL = [NSURL URLWithString:@"http://localhost/company/API"]; 
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:baseURL]; 

[AFNetworkActivityIndicatorManager sharedManager].enabled = YES; 

[objectManager.HTTPClient setDefaultHeader:@"Accept" value:@"application/json"]; 

NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil]; 
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel]; 
objectManager.managedObjectStore = managedObjectStore; 

// Shop Mapping 

RKEntityMapping *shopMapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass([Shop class]) 
                 inManagedObjectStore:objectManager.managedObjectStore]; 
NSDictionary *shopMappingAttributes = [NSDictionary dictionaryWithObjectsAndKeys:@"objectId",@"id",@"name",@"shop",@"city",@"city",nil]; 
shopMapping.identificationAttributes = @[@"objectId"]; 
[shopMapping addAttributeMappingsFromDictionary:shopMappingAttributes]; 
[objectManager addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:shopMapping 
                      pathPattern:@"/shops" 
                       keyPath:nil 
                      statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]]; 


// Item Mapping 

RKEntityMapping *itemMapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass([Item class]) 
                 inManagedObjectStore:objectManager.managedObjectStore]; 
NSDictionary *itemMappingAttributes = [NSDictionary dictionaryWithObjectsAndKeys:@"objectId",@"id",@"name", @"name",@"manufacturer",@"manufacturer",nil]; 
itemMapping.identificationAttributes = @[@"objectId"]; 
[itemMapping addAttributeMappingsFromDictionary:itemMappingAttributes]; 

// Define the relationship mapping 

[objectManager addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:itemMapping 
                      pathPattern:@"/items" 
                       keyPath:nil 
                      statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]]; 

... 

ItemsTableViewController.m

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    // Update Shops 
    [[RKObjectManager sharedManager] getObjectsAtPath:@"/shops" 
             parameters:nil 
              success:nil 
              failure:^(RKObjectRequestOperation *operation, NSError *error) { 
               NSLog(@"Error: %@",error); 
              }]; 

    // Update/Get Items 
    NSDictionary *parameters = @{ 
          @"username": self.username, 
          @"password": self.password, 
          @"API_key": @"abc123", 
          }; 

    NSMutableURLRequest *request = [[RKObjectManager sharedManager] requestWithObject:nil 
                      method:RKRequestMethodPOST 
                      path:@"/items" 
                     parameters:parameters]; 

    RKManagedObjectRequestOperation *operation = [[RKObjectManager sharedManager] managedObjectRequestOperationWithRequest:request managedObjectContext:[RKManagedObjectStore defaultStore].mainQueueManagedObjectContext 
                    success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) { 
                     Item *item = [mappingResult firstObject]; 
                     NSLog(@"Mapped the Item: %@", item); 
                    } failure:^(RKObjectRequestOperation *operation, NSError *error) { 
                     NSLog(@"Error: %@",error); 
                    }]; 
    NSOperationQueue *operationQueue = [NSOperationQueue new]; 
    [operationQueue addOperation:operation]; 
} 

EDIT: Wain, ho questo nel posto di rilievo nel delegato app, ma ottenere un NSException

NSEntityDescription *itemEntity = [NSEntityDescription entityForName:@"Item" inManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext]; 
NSRelationshipDescription *shopRelationship = [itemEntity relationshipsByName][@"shop"]; 
RKConnectionDescription *connection = [[RKConnectionDescription alloc] initWithRelationship:shopRelationship attributes:@{ @"shopId": @"objectId" }]; 
[itemMapping addConnection:connection]; 

NSException

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+entityForName: nil is not a legal NSManagedObjectContext parameter searching for entity name 'Item'' 

Che cosa ho mancato?

risposta

5

È necessario aggiungere un attributo transitorio all'elemento (denominato shopId) e una mappatura associata.

Configurare il rapporto con la mappatura di chiave esterna come:

NSEntityDescription *itemEntity = [NSEntityDescription entityForName:@"Item" inManagedObjectContext:managedObjectContext]; 
NSRelationshipDescription *shopRelationship = [itemEntity relationshipsByName][@"shop"]; 
RKConnectionDescription *connection = [[RKConnectionDescription alloc] initWithRelationship:shopRelationship attributes:@{ @"shopId": @"id" }]; 

Quindi utilizzare addConnection: per aggiungerlo alla tua mappatura.

+0

grazie a @Wain. Questo snippet di codice andrebbe nel Delegato app o nel controller di visualizzazione? Andy – Andy

+0

Aggiungilo a 'itemMapping' dove in precedenza hai provato ad aggiungere un mapping delle relazioni (ma per un elemento annidato). – Wain

+0

Ricevo un'eccezione: vedi modifica. È perché non ho creato l'attributo transitorio sull'elemento? Se é cosi, come? Andy – Andy

Problemi correlati