2010-01-04 7 views
1

Je suis en train d'écrire une application qui a besoin de la possibilité de modifier et de conserver diverses données. J'ai décidé d'utiliser Core Data à cette fin. Lorsque l'utilisateur ouvre l'application pour la première fois que j'ai besoin d'importer une grande quantité de données à partir d'une base de données sqlite, ces données sont composées des relations plusieurs-à-plusieurs.Core Data "Upsert" de base de données SQLite

Je voudrais trouver la meilleure façon d'insérer toutes ces données dans mon magasin de données de code. Actuellement, j'utilise une NSOperation pour faire l'importation alors que le reste de l'application reste actif, donc l'utilisateur peut faire d'autres choses, mais j'aimerais que l'importation se fasse le plus rapidement possible pour que l'application entière soit accessible immédiatement . La méthode que j'utilise maintenant est d'utiliser un NSFetchRequest pour tenter de trouver l'entité associée dans le magasin de données, si l'entité est là, je l'ajoute juste comme une relation, si l'entité n'est pas là, je crée un nouveau et l'ajouter comme une relation. Cela fonctionne, mais je pense que ce n'est probablement pas proche de l'optimum.

Le code J'utilise maintenant:

- (void)importEntitiesIntoContext: (NSManagedObjectContext*)managedObjectContext 
{ 
    // Setup the database object 
    static NSString* const databaseName = @"DBName.sqlite"; 
    NSString* databasePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent: databaseName]; 

    sqlite3* database; 

    // Open the database from the user's filessytem 
    if (sqlite3_open_v2([databasePath UTF8String], &database, SQLITE_OPEN_READONLY, NULL) == SQLITE_OK) 
    { 
     // Setup the SQL Statement 
     NSString* sqlStatement = [NSString stringWithFormat: @"SELECT some_columns FROM SomeTable;"]; 

     sqlite3_stmt* compiledStatement; 
     if (sqlite3_prepare_v2(database, [sqlStatement UTF8String], -1, &compiledStatement, NULL) == SQLITE_OK) 
     { 
      // Create objects to test for existence of exercises 
      NSPredicate* predicate = [NSPredicate predicateWithFormat: @"something == $SOME_NAME"]; 

      NSEntityDescription* entityDescription = [NSEntityDescription entityForName: @"SomeEntity" 
                   inManagedObjectContext: managedObjectContext]; 
      NSFetchRequest* fetchRequest = [[[NSFetchRequest alloc] init] autorelease]; 
      [fetchRequest setEntity: entityDescription]; 

      // Loop through the results and add them to the feeds array 
      while (sqlite3_step(compiledStatement) == SQLITE_ROW) 
      { 
       NSString* someName = [NSString stringWithCharsIfNotNull: (char*)sqlite3_column_text(compiledStatement, 1)]; 
       NSPredicate* localPredicate = [predicate predicateWithSubstitutionVariables: 
               [NSDictionary dictionaryWithObject: someName 
                      forKey: @"SOME_NAME"]]; 
       [fetchRequest setPredicate: localPredicate]; 

       NSError* fetchError; 
       NSArray* array = [managedObjectContext executeFetchRequest: fetchRequest 
                    error: &fetchError]; 
       if (array == nil) 
       { 
        // handle error 
       } 
       else if ([array count] == 0) 
       { 
        SomeEntity* entity = 
        [NSEntityDescription insertNewObjectForEntityForName: @"SomeEntity" 
                inManagedObjectContext: managedObjectContext]; 
        entity.name = someName; 

// **here I call a method that attempts to add the relationships(listed below)** 

       } 
       else 
       { 
        // Some entity already in store 
       } 

      } 
     } 
     else 
     { 
      NSLog(@"sqlStatement failed: %@", sqlStatement); 
     } 

     // Release the compiled statement from memory 
     sqlite3_finalize(compiledStatement); 
    } 

    // All the data has been imported into this temporary context, now save it 
    NSError *error = nil; 
    if (![managedObjectContext save: &error]) 
    { 
     NSLog(@"Unable to save %@ - %@", [error localizedDescription]); 
    } 
} 

Méthode d'ajouter les relations:

- (void)setRelationshipForEntity: (Entity*)entity 
      inManagedObjectContext: (NSManagedObjectContext*)managedObjectContext 
        usingDatabase: (sqlite3*)database 
         entityId: (NSNumber*)entityId 
{ 

    // Setup the SQL Statement and compile it for faster access 
    NSString* sqlStatement = [NSString stringWithFormat: @"SELECT Relationship.name FROM Relationship JOIN Entitys_Relationship ON Entitys_Relationship.id_Relationship = Relationship.id JOIN Entitys ON Entitys_Relationship.id_Entitys = Entitys.id WHERE Entitys.id = %d;", [entityId integerValue]]; 

    sqlite3_stmt* compiledStatement; 
    if (sqlite3_prepare_v2(database, [sqlStatement UTF8String], -1, &compiledStatement, NULL) == SQLITE_OK) 
    { 
     // Create objects to test for existence of relationship 
     NSPredicate* predicate = [NSPredicate predicateWithFormat: @"relationshipName == $RELATIONSHIP_NAME"]; 

     NSEntityDescription* entityDescription = [NSEntityDescription entityForName: @"EntityRelationship" 
                  inManagedObjectContext: managedObjectContext]; 
     NSFetchRequest* fetchRequest = [[[NSFetchRequest alloc] init] autorelease]; 
     [fetchRequest setEntity: entityDescription]; 

     while (sqlite3_step(compiledStatement) == SQLITE_ROW) 
     { 
      NSString* relationshipName = [NSString stringWithCharsIfNotNull: (char*)sqlite3_column_text(compiledStatement, 0)]; 
      NSPredicate* localPredicate = [predicate predicateWithSubstitutionVariables: 
              [NSDictionary dictionaryWithObject: relationshipName 
                     forKey: @"RELATIONSHIP_NAME"]]; 
      [fetchRequest setPredicate: localPredicate]; 

      NSError* fetchError; 
      NSArray* array = [managedObjectContext executeFetchRequest: fetchRequest 
                   error: &fetchError]; 
      if (array == nil) 
      { 
       // handle error 
      } 
      else if ([array count] == 0) 
      { 
       EntityRelationship* entityRelationship = 
       [NSEntityDescription insertNewObjectForEntityForName: @"EntityRelationship" 
               inManagedObjectContext: managedObjectContext]; 
       entityRelationship.relationshipName = relationshipName; 

       [entity addRelationshipObject: entityRelationship]; 
       //NSLog(@"Inserted relationship named %@", relationshipName); 
      } 
      else 
      { 
       [entity addRelationship: [NSSet setWithArray: array]]; 
      } 
     } 
    } 
    else 
    { 
     NSLog(@"slqStatement failed: %@", sqlStatement); 
    } 

    // Release the compiled statement from memory 
    sqlite3_finalize(compiledStatement); 
} 

Répondre

1

Où est la base de données originale vient?

En règle générale, vous convertissez toutes vos données en données de base pendant le développement, puis expédiez l'application avec un magasin de données de base pré-rempli (pas besoin d'attendre une importation pour un utilisateur).

+0

l'information est dans une base de données sqlite, l'utilisateur sera en mesure de modifier les informations sur leur appareil personnel, mais pour les mises à jour de l'application, les données devront être fusionnées avec de nouvelles données. – jessecurry

+0

Je l'aurais toujours pour que la fusion se fasse entre le magasin de données principales d'un utilisateur sur l'appareil et le magasin initial de données de base mis à jour de l'application, mais c'est parce que je préfère travailler avec Core Data. – gerry3

+0

Quelle méthode utilisez-vous généralement pour créer le magasin CoreData initial? – jessecurry

2

Apple a quelques suggestions sur la façon d'optimiser les grandes importations dans un magasin de données de base:

  • Désactiver le undo-manager lors de l'importation de lots
  • Ne pas insérer enregistrement par enregistrement - Créer des lots de taille n (selon la taille du disque)
  • Utilisez une piscine autorelease local et égoutter après chaque lot

Voir la documentation pour les détails.