2009-08-29 19 views
57

Mam problem ze zrozumieniem tego materiału Core Data. Jak utworzyć nowy wpis z unikalnym identyfikatorem? W SQL zadeklarowałbym tylko jedno pole jako pole autoinkrementacji. Nie widzę tutaj nic takiego, ale mógłbym czegoś nie zauważyć. Chcę po prostu automatycznie zwiększać pole NSInteger, więc gdy ręcznie dodaję elementy do bazy danych, będę miał jakąś referencję do nich.Tworzenie unikalnego identyfikatora dla programu Core Data na iPhonie

Odpowiedz

28

To nie działa jak CoreData.

W CoreData tworzysz instancje encji. Każda instancja jest unikalna. Następnie pobierasz i manipulujesz instancjami w razie potrzeby. CoreData dba o trwałość, w tym o unikatowe identyfikatory.

Odejdź od wszystkiego, co wiesz o tradycyjnych relacyjnych bazach danych.

Uruchom here.

Następnie przejdź here.

W szczególności, this.

CoreData to niesamowicie potężna technologia, która oferuje funkcje znacznie wykraczające poza samą bazę danych, takie jak trwałość. Zaoszczędzi ci to wiele linii kodu i sprawdzi się wyjątkowo dobrze, jeśli go obejmiesz.

+3

Nie zgadzam się z "krokiem od wszystkiego, co wiesz". Istnieją przypadki, w których możesz otrzymać unikalne jednostki bez właściwości odróżniających (usuń serwer, który nie przestrzega reguł). Posiadanie auto-inkrementacji przydałoby się tutaj. – ray

+0

Czy przeczytałeś ostatnie zdanie w pytaniu OP ("Będę miał jakąś referencję do nich.")? Nie potrzebujesz do tego pola automatycznie powiększającego. Dla unikalnych identyfikatorów jednostek są już wbudowane dane podstawowe. Z pewnością istnieją powody, dla których możesz chcieć, aby pole automatycznie się zwiększało, ale robiąc to w celu uniknięcia identyfikacji, po prostu wymyślasz ponownie koło. Z pewnością możesz zrobić to dla korelacji z klienta do serwera, ale tylko wtedy, gdy serwer nie może pobrać identyfikatora URI już obsługiwanego przez NSManagedObjectID. – bbum

+0

@ DanBeaulieu Sigh. Naprawdę chciałbym, żeby Apple nie łamało linków przez cały czas. Spróbuję znaleźć czas, żeby je naprawić. – bbum

141

Chociaż zgadzam się z tym, co powiedziałeś, za podstawowymi danymi kryje się mechanizm ID. ID rzeczywiście zarządza Rdzeń-danych, ale można je odzyskać z:

NSManagedObjectID *moID = [managedObject objectID]; 

Aby uzyskać więcej informacji zobacz: Core Data Programming Guide

+21

To żal, że pytający nigdy nie przyjął tak wspaniałej odpowiedzi. – RonLugge

+0

To było dokładnie to, czego potrzebowałem ponad 2 lata później. Również za pomocą URIRepresentation z NSManagedObjectID można łatwo przechowywać je w NSUserDefaults, jak było to konieczne dla mnie w schemacie buforowania.^1 –

+2

Należy pamiętać, że objectID może i zmienia się, szczególnie w przypadku migracji. Nie należy polegać na tym, aby ta wartość była spójna między jednym uruchomieniem aplikacji a następnym. - Komentarz Marcusa S Zarry w innym wątku. – Mateus

2

Co jeśli chcemy synchronizować z odległej bazy danych, która nie potrzebuje autoincremented id za wyjątkowy rzędy danych? Czy istnieje sposób, aby zaimplementować autoinkremented id, jeśli zajdzie taka potrzeba. Rozumiem, że nie jest to wymagane w przypadku danych podstawowych, ale muszę zaimportować dane ze zdalnej bazy danych, a następnie przesłać ponownie i upewnić się, że id są nienaruszone.

+1

W tym przypadku użyłbym dwóch identyfikatorów i zapisałbym identyfikator automatycznego zwiększania serwera jako atrybut podstawowego modelu danych. – Tony

+0

Użyj dowolnej strony serwera, aby jednoznacznie zidentyfikować rekordy; dodanie na górze numeru z automatyczną inkrementacją będzie z pewnością działało (Łukasz zapewnia bardzo nieefektywne rozwiązanie), ale jest to kolejny szczegół, który należy przełamać w przyszłości. – bbum

6

Spójrz na: [[NSProcessInfo processInfo] globallyUniqueString].

Dokumentacja Apple: Globalny identyfikator procesu. Identyfikator zawiera nazwę hosta, identyfikator procesu i sygnaturę czasową, która zapewnia, że ​​identyfikator jest unikalny dla sieci, co jest przydatne, jeśli nie chcesz, aby użytkownicy odgadywali identyfikator.

10

Ta funkcja klasy zwróci następny dostępny numer dla swojej właściwości id (musi to być właściwość całkowita).

Ja nazywam to generatorem wartości auto-increment. Wciąż zgadzam się z innymi, że istnieje objectID, ale czasami potrzebujesz numeru.

Możesz umieścić tę funkcję w swojej podklasy NSManagedObject dla podmiotu:

+(NSNumber *)nextAvailble:(NSString *)idKey forEntityName:(NSString *)entityName inContext:(NSManagedObjectContext *)context{ 


    NSFetchRequest *request = [[NSFetchRequest alloc] init]; 
    NSManagedObjectContext *moc = context; 
    NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:moc]; 

    [request setEntity:entity]; 
    // [request setFetchLimit:1]; 

    NSArray *propertiesArray = [[NSArray alloc] initWithObjects:idKey, nil]; 
    [request setPropertiesToFetch:propertiesArray]; 
    [propertiesArray release], propertiesArray = nil; 

    NSSortDescriptor *indexSort = [[NSSortDescriptor alloc] initWithKey:idKey ascending:YES]; 
    NSArray *array = [[NSArray alloc] initWithObjects:indexSort, nil]; 
    [request setSortDescriptors:array]; 
    [array release], array = nil; 
    [indexSort release], indexSort = nil; 

    NSError *error = nil; 
    NSArray *results = [moc executeFetchRequest:request error:&error]; 
    // NSSLog(@"Autoincrement fetch results: %@", results); 
    NSManagedObject *maxIndexedObject = [results lastObject]; 
    [request release], request = nil; 
    if (error) { 
     NSLog(@"Error fetching index: %@\n%@", [error localizedDescription], [error userInfo]); 
    } 
    //NSAssert3(error == nil, @"Error fetching index: %@\n%@", [error localizedDescription], [error userInfo]); 

    NSInteger myIndex = 1; 
    if (maxIndexedObject) { 
     myIndex = [[maxIndexedObject valueForKey:idKey] integerValue] + 1; 
    } 

    return [NSNumber numberWithInteger:myIndex]; 
} 
+0

Doskonały kolega z rozwiązania. Twoje zdrowie !! –

+2

Aby dokonać tego, sortuj według indeksu malejącego, a następnie ustaw limit pobierania na 1. tj. 'NSSortDescriptor * indexSort = [[NSSortDescriptor alloc] initWithKey: idKey rosnąco: NO];' a następnie odkomentuj 'request.fetchLimit = 1; ' –

+0

Prawie perfekcyjnie! Jeszcze lepiej z optymalizacją @JasonMoore! – John

6

Oto trzy rodzaje unikalnej reprezentacji ID obiektu CoreData:

NSManagedObjectID *taskID = [task objectID]; 
NSURL *taskUniqueURLKey = task.objectID.URIRepresentation; 
NSString *taskUniqueStringKey = task.objectID.URIRepresentation.absoluteString; 

!!!! UWAGA: Jeśli chcesz użyć powyższego unikalnego klucza jako indeksu, upewnij się, że obiekt jest zapisany w kontekście przed użyciem, lub identyfikator obiektu będzie tymczasowym identyfikatorem, który zostanie zastąpiony później (np. po zapisaniu). Zobacz dokument jabłko klasy NSManagedObjectID:

- (BOOL)isTemporaryID; // indicates whether or not this ID will be replaced later, 
such as after a save operation (temporary IDs are assigned to newly inserted objects 
and replaced with permanent IDs when an object is written to a persistent store); most 
IDs return NO 
1

Update do @Lukasz odpowiedź w SWIFT:

static func nextAvailble(_ idKey: String, forEntityName entityName: String, inContext context: NSManagedObjectContext) -> Int { 
    let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: entityName) 
    fetchRequest.propertiesToFetch = [idKey] 
    fetchRequest.sortDescriptors = [NSSortDescriptor(key: idKey, ascending: true)] 

    do { 
     let results = try context.fetch(fetchRequest) 
     let lastObject = (results as! [NSManagedObject]).last 

     guard lastObject != nil else { 
      return 1 
     } 

     return lastObject?.value(forKey: idKey) as! Int + 1 

    } catch let error as NSError { 
     //handle error 
    } 

    return 1 
} 
0

dane Rdzeń służy do ram oporność, to ramy abstrahuje klucz podstawowy.

Każdy obiekt NSManagedObject ma wbudowany własny unikalny klucz, który jest dostępny w jego właściwości objectID.

Ten identyfikator służy wewnętrznie do łączenia podmiotów przez swoje powiązania. Nie ma potrzeby utrzymywania własnego identyfikatora jako klucza podstawowego, tak jak w przypadku SQL.

Zawsze można uzyskać identyfikator identyfikatora NSManagedObject.object. i pobieranie kontekstu obiektu za pomocą NSMananagedObjectContext.objectWithId

Powiązane problemy