2010-01-04 54 views
1

我目前正在编写一个需要修改和保存各种数据片段的应用程序。我决定为此使用Core Data。 当用户首次打开应用程序时,我需要从sqlite数据库导入大量数据,这些数据由多对多关系组成。来自SQLite数据库的核心数据“Upsert”

我想找出将所有这些数据插入我的代码数据存储的最佳方法。现在,我正在使用NSOperation来执行导入,而应用程序的其余部分仍处于活动状态,因此用户可以执行其他操作,但我希望导入过程尽快发生,以便可以立即访问整个应用程序。

我现在使用的方法是使用NSFetchRequest尝试在数据存储中查找相关实体,如果实体在那里,我只是将它作为关系添加,如果实体不存在,我创建一个新的,并添加它作为一种关系。这有效,但我觉得它可能不是最佳的。

的代码我现在使用:

- (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]); 
    } 
} 

方法添加的关系:

- (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); 
} 

回答

1

哪里原始数据库是从哪里来的?

通常,您可以在开发期间将所有数据转换为核心数据,然后将应用程序与预先填充的核心数据存储一起发送(不需要用户等待导入)。

+0

信息是在sqlite数据库中,用户将能够更改其个人设备上的信息,但对于应用程序更新,数据将需要与新数据合并。 – jessecurry 2010-01-04 17:54:14

+0

我仍然会这样做,以便合并在设备上的用户Core Data存储和应用程序的更新初始Core Data存储之间,但这是因为我更喜欢使用Core Data。 – gerry3 2010-01-04 18:05:30

+0

您通常使用什么方法创建初始CoreData存储? – jessecurry 2010-01-05 00:26:37

2

苹果公司如何大量进口到优化核心数据存储的一些建议:

  • 批量导入过程中禁用撤消经理
  • 不要插入记录的记录 - 创建的批次大小n(根据记录大小)
  • 使用本地自动释放池每批

后沥干它见documentation的细节。