2012-12-06 12 views
5

Potrzebuję wykonać operację typu "dołącz" na dwóch tabelach/modelach z mojego magazynu danych podstawowych i mam problem ze znalezieniem dobrych przykładów na uzyskanie czegoś tak to działa.Podstawowe dane - proste pobieranie typu JOIN

To dość proste, co muszę zrobić. Mam dwa modele/tabele: lokalizacje i location_categories, w których lokalizacje zawierają szczegóły lokalizacji/zakładu (wraz z unikalnym identyfikatorem), a tabela location_categories zawiera identyfikator category_id z powiązanymi id_właściwości. Muszę wybrać wszystkie lokalizacje, w których, biorąc pod uwagę identyfikator category_id, dołącza ona do dwóch tabel/modeli. Gdyby to było proste SQL, to będzie wyglądać następująco (i ta kwerenda działa gdy uruchamiam go przed faktycznym DB SQLite):

// pretend we passed in a catID of 29: 
SELECT * FROM zlocation where zlocid in (select zlocid from zloccategory where zcatid = 29) 

Więc jak widać, to dość prosta. Czy istnieje sposób, aby to zrobić bez konieczności wykonywania dwóch przydziałów i pętli for? Mój obecny kod celu do zrobienia tego jest poniżej i działa dobrze, ale oczywiście jest strasznie powolny i nieefektywny, ze względu na dużą ilość danych znajdujących się w obu tabelach. For-pętle powodują ogromne spowolnienie, a mój gut mówi mi, że ta praca naprawdę należy zrobić po stronie DB/Core danych rzeczy:

- (NSMutableArray *) fetchLocsWithCatID:(NSString *)catID { 
    NSMutableArray *retArr = [[NSMutableArray alloc] init]; 

    NSManagedObjectContext *context = [self managedObjectContext]; 
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
    [fetchRequest setEntity:[NSEntityDescription entityForName:MODELNAME_LOCCATEGORIES inManagedObjectContext:context]]; 
    [fetchRequest setPredicate: [NSPredicate predicateWithFormat:@"catID == %@", catID]]; 

    NSError *error; 
    NSArray *locCats = [context executeFetchRequest:fetchRequest error:&error]; 
    NSArray *allLocsArr = [self fetchAllDataForTable:MODELNAME_LOCATION]; // this retrieves contents of entire table 

    for (Location *currLoc in allLocsArr) { 
     for (LocCategory *currLocCat in locCats) { 
      if ([currLoc.locID isEqualToString:currLocCat.locID]) { 
       if (![retArr containsObject:currLoc]) { 
        [retArr addObject:currLoc]; 
       } 
      } 
     } 
    } 

    return retArr; 
} 

jakieś przemyślenia na temat tego, czy jest to możliwe w jednym predicate/fetch? Czy może nie ma lepszego sposobu na połączenie tych dwóch NSArrays poprzez kod celu?

Z góry dziękuję za wszelkie wskazówki, które możesz w tej sprawie zaoferować!

Odpowiedz

3

Najlepszym sposobem byłoby wykorzystanie relacji.

W ten sposób, kiedy sprowadzić Location można również uzyskać dostęp do LocationCategory jak myLocation.locationCategory

Trzeba by skonfigurować relationsship tak:

(Entity)LocationCategory.(relationship)locations <->> (Entity)Location.(relationship)locationCategory 

jest to stosunek do-wielu. Nie zapomnij także o odwrotności.

Po skonfigurowaniu wystarczy połączyć relacje w miejscu, w którym kiedykolwiek tworzysz instancje encji. Podobnie jak:

Location *myLocation = ... 
LocationCategory *myLocationCategory = ... 
myLocation.locationCategoy = myLocationCategory; 

Upewnij się, że używasz tego samego MOC do pobrania obiektów.Gorąco polecam MagicalRecord, aby łatwo zarządzać tworzeniem obiektów i pobierać w określonym moc.

+0

Zaznaczam to jako najlepszą odpowiedź, ponieważ wspomniałeś o potrzebie połączenia również relacji. To było coś, co mnie jeszcze nie zaskoczyło, nawet po tym, jak zaimplementowałem relacje w modelu. Dziękuję Ci! – svguerin3

2

Przeczytaj o podstawowych danych i relacjach. Automatycznie utworzy Zestaw innych obiektów powiązanych obiektów. Tak więc w powyższym przypadku, jeśli masz Lokalizacje jako jeden obiekt, Location_Categories jako inną kategorię, wszystko, co musisz zrobić, to utworzyć relację w tabeli Lokalizacje, która wskaże na kategorię Lokalizacja.

Możesz to zrobić na ekranie modelowania danych podstawowych.

Po wykonaniu tej czynności klasa obiektu zarządzanego w lokalizacji będzie miała NSSet kategorii lokalizacji. Podobnie, Kategorie lokalizacji Jednostka będzie miała obiekt Lokalizacja w nim.

Wszystko, co musisz zrobić, to jedno zapytanie z kategorii lokalizacji, podobnie jak powyżej. Jednak zamiast wykonywać dodatkowe zapytania, należy wykonać jeden z podstawowych samouczków danych, aby uzyskać pomoc w tym zakresie. Należy to zrobić.

+0

Świetne, dziękuję! Czuję się jak idiota za unikanie używania relacji w moim modelu. Myślałem, że nie ma sensu, ale teraz widzę sens. :) Nie miałem pojęcia, że ​​relacje mogą być używane w ten sposób (jestem dość nowy w Core Data). Teraz działa dobrze. Jeszcze raz dziękuję za pomoc i czas! – svguerin3

1

Jeśli te jednostki zostały zamodelowane w CoreData, zazwyczaj masz powiązanie z location_categories do lokalizacji, z odwrotną relacją z lokalizacji do location_categories. Gdybym miał obiekt o nazwie "Lokalizacja", miałby w nim powiązanie o nazwie locationCategory, a w obiekcie LocationCategory miałby relację o nazwie Location.

Z tego rodzaju dwukierunkowej relacji określonej, chciałbym następnie skonfigurować pobrać wniosek użyciu coś takiego:

[fetchRequest setEntity:[NSEntityDescription entityForName:MODELNAME_LOCATIONS inManagedObjectContext:context]]; 
[fetchRequest setPredicate: [NSPredicate predicateWithFormat:@"locationCategory.catID == %@", catID]]; 

To powinno zwrócić wszystkie obiekty, miejsca, które są związane z kategorią lokalizacji z danym kategoria ID

Powiązane problemy