database - 记录未保存到核心数据 sqlite 文件中

标签 database sqlite core-data ios5 import

对于 iOS 编程,我完全是个新手,更不用说核心数据了。这对我来说相当不直观,因为我真正熟悉了 MATLAB 编程,我认为 MATLAB 更像是一种“脚本”语言。

无论如何,我的问题是我不知道我必须做什么才能为我的应用程序创建数据库。所以我读了一点,认为我必须为我的东西创建一个 SQL 数据库,然后导入它。长话短说,我创建了一个 SQLite 数据库,我想使用已经完成的工作将内容导入到我的 CoreData 数据库中。

我尝试导出到逗号分隔的文件和 xml 文件并读取它们,但我不喜欢它,而且这似乎是我不需要执行的额外步骤。

因此,我将 SQLite 数据库导入到我的资源中并添加了 sqlite 框架。

我已经设置了核心数据模型,并且它正在后台正确地为模型设置 SQLite 数据库。

当我运行程序以将对象添加到实体时,它似乎有效,之后我什至可以获取结果。但是,当我检查核心数据数据库 SQLite 文件时,没有保存任何记录。

它怎么可能获取结果但不将其保存到数据库中?

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
//load in the path for resources
NSString *paths = [[NSBundle mainBundle] resourcePath];
NSString *databaseName = @"histology.sqlite";
NSString *databasePath = [paths stringByAppendingPathComponent:databaseName];
[self createDatabase:databasePath ];

NSError *error;
if ([[self managedObjectContext] save:&error]) {
    NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
}

// Test listing all CELLS from the store
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entityMO = [NSEntityDescription entityForName:@"CELL"
                                            inManagedObjectContext:[self managedObjectContext]];
[fetchRequest setEntity:entityMO];
NSArray *fetchedObjects = [[self managedObjectContext] executeFetchRequest:fetchRequest error:&error];
for (CELL *cellName in fetchedObjects) {
    //NSLog(@"cellName: %@", cellName);
}    


-(void) createDatabase:databasePath {
NSLog(@"The createDatabase function was entered.");  
NSLog(@"The databasePath is %@ ",[databasePath description]);
// Setup the database object
sqlite3 *histoDatabase;

// Open the database from filessytem
if(sqlite3_open([databasePath UTF8String], &histoDatabase) == SQLITE_OK) {
        NSLog(@"The database was opened");
    // Setup the SQL Statement and compile it for faster access
    const char *sqlStatement = "SELECT * FROM CELL";
    sqlite3_stmt *compiledStatement;

    if(sqlite3_prepare_v2(histoDatabase, sqlStatement, -1, &compiledStatement, NULL) != SQLITE_OK) {
        NSAssert1(0, @"Error while creating add statement. '%s'", sqlite3_errmsg(histoDatabase));
    }

    if(sqlite3_prepare_v2(histoDatabase, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {

        // Loop through the results and add them to cell MO array
        while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
            CELL *cellMO = [NSEntityDescription insertNewObjectForEntityForName:@"CELL" inManagedObjectContext:[self managedObjectContext]];


            if (sqlite3_column_type(compiledStatement, 0) != SQLITE_NULL) {
                cellMO.cellName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 0)];
            } else {
                cellMO.cellName = @"undefined";
            }

            if (sqlite3_column_type(compiledStatement, 1) != SQLITE_NULL) {
                cellMO.cellDescription = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
            } else {
                cellMO.cellDescription = @"undefined";
            }

                NSLog(@"The contents of NSString *cellName = %@",[cellMO.cellName   description]);

        }
    }


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

}
sqlite3_close(histoDatabase);
}

我感觉这与打开/关闭两个数据库的时间有关?

附件我有一些 SQL 调试输出到终端

2012-05-28 16:03:39.556 MedPix[34751:fb03] The createDatabase function was entered.

2012-05-28 16:03:39.557 MedPix[34751:fb03] The databasePath is /Users/jack/Library/Application Support/iPhone Simulator/5.1/Applications/A6B2A79D-BA93-4E24-9291-5B7948A3CDF4/MedPix.app/histology.sqlite 

2012-05-28 16:03:39.559 MedPix[34751:fb03] The database was opened

2012-05-28 16:03:39.560 MedPix[34751:fb03] The database was prepared

2012-05-28 16:03:39.575 MedPix[34751:fb03] CoreData: annotation: Connecting to sqlite database file at "/Users/jack/Library/Application Support/iPhone Simulator/5.1/Applications/A6B2A79D-BA93-4E24-9291-5B7948A3CDF4/Documents/MedPix.sqlite"

2012-05-28 16:03:39.576 MedPix[34751:fb03] CoreData: annotation: creating schema.

2012-05-28 16:03:39.577 MedPix[34751:fb03] CoreData: sql: pragma page_size=4096

2012-05-28 16:03:39.578 MedPix[34751:fb03] CoreData: sql: pragma auto_vacuum=2

2012-05-28 16:03:39.630 MedPix[34751:fb03] CoreData: sql: BEGIN EXCLUSIVE

2012-05-28 16:03:39.631 MedPix[34751:fb03] CoreData: sql: SELECT TBL_NAME FROM SQLITE_MASTER WHERE TBL_NAME = 'Z_METADATA'

2012-05-28 16:03:39.632 MedPix[34751:fb03] CoreData: sql: CREATE TABLE ZCELL ( Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER, Z_OPT INTEGER, ZCELLDESCRIPTION VARCHAR, ZCELLNAME VARCHAR ) 
...

2012-05-28 16:03:39.669 MedPix[34751:fb03] CoreData: annotation: Creating primary key table.

2012-05-28 16:03:39.671 MedPix[34751:fb03] CoreData: sql: CREATE TABLE Z_PRIMARYKEY (Z_ENT INTEGER PRIMARY KEY, Z_NAME VARCHAR, Z_SUPER INTEGER, Z_MAX INTEGER)

2012-05-28 16:03:39.672 MedPix[34751:fb03] CoreData: sql: INSERT INTO Z_PRIMARYKEY(Z_ENT, Z_NAME, Z_SUPER, Z_MAX) VALUES(1, 'CELL', 0, 0)
...

2012-05-28 16:03:39.701 MedPix[34751:fb03] CoreData: sql: CREATE TABLE Z_METADATA (Z_VERSION INTEGER PRIMARY KEY, Z_UUID VARCHAR(255), Z_PLIST BLOB)

2012-05-28 16:03:39.702 MedPix[34751:fb03] CoreData: sql: SELECT TBL_NAME FROM SQLITE_MASTER WHERE TBL_NAME = 'Z_METADATA'

2012-05-28 16:03:39.703 MedPix[34751:fb03] CoreData: sql: DELETE FROM Z_METADATA WHERE Z_VERSION = ?

2012-05-28 16:03:39.704 MedPix[34751:fb03] CoreData: sql: INSERT INTO Z_METADATA (Z_VERSION, Z_UUID, Z_PLIST) VALUES (?, ?, ?)

2012-05-28 16:03:39.705 MedPix[34751:fb03] CoreData: sql: COMMIT

2012-05-28 16:03:39.710 MedPix[34751:fb03] CoreData: sql: pragma cache_size=200

2012-05-28 16:03:39.711 MedPix[34751:fb03] CoreData: sql: SELECT Z_VERSION, Z_UUID, Z_PLIST FROM Z_METADATA

2012-05-28 16:03:39.712 MedPix[34751:fb03] The contents of NSString *cellName = Beta Cell

2012-05-28 16:03:39.712 MedPix[34751:fb03] The contents of NSString *cellName = Gastric Chief Cell

...

2012-05-28 16:03:39.714 MedPix[34751:fb03] The database was prepared

2012-05-28 16:03:39.764 MedPix[34751:fb03] The createDatabase function has finished. Now fetching.

2012-05-28 16:03:39.765 MedPix[34751:fb03] CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZCELLDESCRIPTION, t0.ZCELLNAME FROM ZCELL t0 

2012-05-28 16:03:39.766 MedPix[34751:fb03] CoreData: annotation: sql connection fetch time: 0.0008s

2012-05-28 16:03:39.767 MedPix[34751:fb03] CoreData: annotation: total fetch execution time: 0.0016s for 0 rows.

2012-05-28 16:03:39.768 MedPix[34751:fb03] cellName: <CELL: 0x6bbc120> (entity: CELL; id: 0x6bbc160 <x-coredata:///CELL/t57D10DDD-74E2-474F-97EE-E3BD0FF684DA34> ; data: {
cellDescription = "S cells are cells which release secretin, found in the jejunum and duodenum. They are stimulated by a drop in pH to 4 or below in the small intestine's lumen. The released secretin will increase the s";
cellName = "S Cell";
organs =     (
);
specimens =     (
);
systems =     (
);
tissues =     (
);
})
...

章节被缩短以简化。但请注意,获取结果包含信息,但它说总获取执行针对“0”行?怎么可能?任何帮助,尤其是详细的解释,将不胜感激。 :) 谢谢。

最佳答案

有几件事。

首先,根据您导入的数据库的大小,您可能希望从主线程中获取导入。否则,如果您在 applicationDidFinishLaunching: 方法中花费很长时间,系统将终止您的应用程序。您可以按如下方式执行此操作:

// If in applicationDidFinishLaunching, we need to first schedule on the main queue
// We do this to be one of the first things scheduled once the main queue starts running
dispatch_async(dispatch_get_main_queue(), ^{
    // now get off the main queue
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{
       [self createDatabase:databasePath];

       // Now put the results back on the main queue
       dispatch_async(dispatch_get_main_queue(), ^{
           NSError *error;
           if ([[self managedObjectContext] save:&error]) {
              NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
           }

       // Test listing all CELLS from the store
           NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
           NSEntityDescription *entityMO = [NSEntityDescription entityForName:@"CELL"
                                        inManagedObjectContext:[self managedObjectContext]];
           [fetchRequest setEntity:entityMO];
           NSArray *fetchedObjects = [[self managedObjectContext] executeFetchRequest:fetchRequest error:&error];
           for (CELL *cellName in fetchedObjects) {
              //NSLog(@"cellName: %@", cellName);
           }
       });    

    });
});

我会检查导入是否已完成,如果没有,则使用 Grand Central Dispatch 将导入工作从主线程中移除。

其次,正如 gerry3 在他的回答中提到的,您需要将 save: 消息发送到您的托管对象上下文。使用 iOS5 的父上下文和子上下文将允许您轻松地通过子上下文在后台导入,然后将这些更改推送到主父上下文。查看 WWDC 2011 核心数据 session 和堆栈溢出以获得良好的概述。

在上面的代码上下文中,您将执行以下所有行:

// create a child context with a concurrent queue type.
NSManagedObjectContext *childManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];

// Set the parentContext.  Now whenever we save changes to the child context
// They will be pushed up to the parentContext and we can choose to save or throw them
// away
childManagedObjectContext.parentContext=self.managedObjectContext;

// Loop through the results and add them to cell MO array
NSInteger rowNumber=0;
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
        CELL *cellMO = [NSEntityDescription insertNewObjectForEntityForName:@"CELL" inManagedObjectContext:[self managedObjectContext]];


   if (sqlite3_column_type(compiledStatement, 0) != SQLITE_NULL) {
        cellMO.cellName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 0)];
   } else {
        cellMO.cellName = @"undefined";
   }

   if (sqlite3_column_type(compiledStatement, 1) != SQLITE_NULL) {
        cellMO.cellDescription = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
   } else {
        cellMO.cellDescription = @"undefined";
   }
   NSLog(@"The contents of NSString *cellName = %@",[cellMO.cellName   description]);

   // Save our records periodically.  Choose a good number of iterations on this.
   // depends on your particular situation.
   if (rowNumber%100==0){
       NSError *mocError=nil;
       // Save the changes on the child context
       // This will push the changes up to the parent context.
       [childManagedObjectContext performBlock:^{
            [self.managedObjectContext save: &mocError];
            if (mocError){
                NSLog(@"mocError on rowNumber:  %d, error:  %@",rowNumber, error);
            }
            // Now save the changes on the parent context

            [self.managedObjectContext performBlock:^{
                    NSError *parentMocError=nil;
                    [self.managedObjectContext save: &parentMocError];
                    if (parentMocError){
                      NSLog(@"parentMocError on rowNumber:  %d, error:  %@",rowNumber, parentMocError);
                    }
             }];

       }];

   }
   rowNumber=rowNumber+1;
}

// Pickup and stragglers
[childManagedObjectContext performBlock:^{
     [self.managedObjectContext save: &mocError];
     if (mocError){
        NSLog(@"mocError on rowNumber:  %d, error:  %@",rowNumber, error);
     }
     // Now save the changes on the parent context

     [self.managedObjectContext performBlock:^{
           NSError *parentMocError=nil;
           [self.managedObjectContext save: &parentMocError];
               if (parentMocError){
                  NSLog(@"parentMocError on rowNumber:  %d, error:  %@",rowNumber, parentMocError);
               }
           }];

 }];

祝你好运!

蒂姆

关于database - 记录未保存到核心数据 sqlite 文件中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10791413/

相关文章:

ios - 请求非结构或联合中的成员 tableView

Cocoa CoreData 和非基于文档的应用程序

database - 在数据库列中存储分隔列表真的那么糟糕吗?

python-3.x - 使用 API 将数据插入到 sqlite3 数据库中

node.js - 哪个是与node.js(express.js)一起使用的最佳数据库

java - SQLite:executeQuery() 返回空结果集

SQLite 将相似记录的值合并为一个

ios - 将多个 CoreData 数据库动态合并为一个虚拟的单一数据库

PHP 检查对其他服务器的请求是否正在运行

sql-server - 订单管理的数据库设计