Iphone 从SQLite中删除和写入,使用JSON数据在MySQL中同步远程表

Iphone 从SQLite中删除和写入,使用JSON数据在MySQL中同步远程表,iphone,mysql,ios,json,sqlite,Iphone,Mysql,Ios,Json,Sqlite,首先,我一直在阅读许多与我相似的问题,甚至从一些人那里得到一些建议,以达到我的目的,所以我感谢stackoverflow用户 好的,对于应用程序的iOS端,我总共有五个SQLite数据库表,对于远程服务器,它们在MySQL中是等价的。我在SQLite表中预加载的数据显示良好,应用程序按预期运行。当我从远程数据库下载JSON数据以替换iOS设备中存储的本地信息时,问题就出现了。我将通过引用一个表来保持简单: // Create an object, reading its informat

首先,我一直在阅读许多与我相似的问题,甚至从一些人那里得到一些建议,以达到我的目的,所以我感谢stackoverflow用户

好的,对于应用程序的iOS端,我总共有五个SQLite数据库表,对于远程服务器,它们在MySQL中是等价的。我在SQLite表中预加载的数据显示良好,应用程序按预期运行。当我从远程数据库下载JSON数据以替换iOS设备中存储的本地信息时,问题就出现了。我将通过引用一个表来保持简单:

    // Create an object, reading its information from the local database.
    Pregunta *objPregunta = [[Pregunta alloc] initWithPrimaryKey:0 database:delegate.database];
    // Erase all data in the object's table (preguntas) see method below.
    [objPregunta deleteAllFromDatabase];
    // Obtain the remote objects retrieved via JSON, and cycle them.
    NSArray *preguntas = (NSArray *)[responseDict objectForKey:@"preguntas"];
    for (id pregunta in preguntas) {
        // Create a dictionary storing the JSON object.
        NSDictionary *pregunta_dict = (NSDictionary *) pregunta;

        // Send the dictionary to the function for SQLite insertion.
        [objPregunta insertNewRecordIntoDatabase:pregunta_dict];
    }
    // Free the object resources.
    [objPregunta release];
这是与上述代码中Pregunta对象关联的SQLite删除函数:

- (void) deleteAllFromDatabase {
    if(delete_statement == nil) {
        const char *sql = "DELETE FROM preguntas";

        if (sqlite3_prepare_v2(database, sql, -1, &delete_statement, NULL) != SQLITE_OK) {
            NSAssert1(0, @"Error: Failed to prepare SQL statement: %s.", sqlite3_errmsg(database));
        }
    }

    if (sqlite3_step(delete_statement) != SQLITE_DONE) {
        NSAssert1(0, @"Failed to save priority with message: %s.", sqlite3_errmsg(database));
    }

    sqlite3_reset(delete_statement);
}
最后,这个函数使用传递给它的dictionary对象将新记录插入数据库:

- (void) insertNewRecordIntoDatabase:(NSDictionary *)pregunta_dict {
    if (insert_statement == nil) {
        const char *sql = "INSERT INTO preguntas (id_forma, numero, seccion, texto, respuesta, comentario, requiere_fotografia, fotografia, tipo) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)";

        self.id_forma            = [[pregunta_dict objectForKey:@"id_forma"] integerValue];
        self.numero              = [[pregunta_dict objectForKey:@"numero"]   integerValue];
       if([pregunta_dict objectForKey:@"seccion"] == [NSNull null]) {
            self.seccion         = nil;
        } else {
            self.seccion         = [pregunta_dict  objectForKey:@"seccion"];
        }
        self.texto               = [pregunta_dict  objectForKey:@"texto"];
        if([pregunta_dict objectForKey:@"respuesta"] == [NSNull null]) {
            self.respuesta       = nil;
        } else {
            self.respuesta       = [pregunta_dict  objectForKey:@"respuesta"];
        }
        if([pregunta_dict objectForKey:@"comentario"] == [NSNull null]) {
            self.comentario      = nil;
        } else {
            self.comentario      = [pregunta_dict  objectForKey:@"comentario"];
        }
        self.requiere_fotografia = [pregunta_dict  objectForKey:@"requiere_fotografia"];
        if([pregunta_dict objectForKey:@"fotografia"] == [NSNull null]) {
            self.fotografia      = nil;
        } else {
            self.fotografia      = [pregunta_dict  objectForKey:@"fotografia"];
        }
        self.tipo                = [pregunta_dict  objectForKey:@"tipo"];

        if (sqlite3_prepare_v2(database, sql, -1, &insert_statement, NULL) != SQLITE_OK) {
            NSAssert1(0, @"Error: Failed to prepare SQL statement: %s.", sqlite3_errmsg(database));
        } else {
            @try {
                sqlite3_bind_int (insert_statement, 1, self.id_forma);
                sqlite3_bind_int (insert_statement, 2, self.numero);
                sqlite3_bind_text(insert_statement, 3, [self.seccion             UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(insert_statement, 4, [self.texto               UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(insert_statement, 5, [self.respuesta           UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(insert_statement, 6, [self.comentario          UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(insert_statement, 7, [self.requiere_fotografia UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(insert_statement, 8, [self.fotografia          UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(insert_statement, 9, [self.tipo                UTF8String], -1, SQLITE_TRANSIENT);
            }
            @catch (NSException *exception) {
                ;
            }
        }
    }

    if (sqlite3_step(insert_statement) != SQLITE_DONE) {
        NSAssert1(0, @"Failed to prepare SQL statement: %s.", sqlite3_errmsg(database));
    } else {
    NSLog(@"Pregunta insert_id: %lld", sqlite3_last_insert_rowid(database));
    }

    sqlite3_reset(insert_statement);
}
现在,代码的问题在于,它似乎插入的行不正确,因为当所有表的删除/插入过程完成,并且我从SQLite读取插入的数据时,我在数据库中的值会重复

我认为它与
deleteAllFromDatabase
函数有关,但它似乎过于简单,不会引起任何麻烦。我还试图直接指定要为主键存储哪些值,但应用程序崩溃了,因为显然没有满足约束条件(我没有外键,每个表上只有一个主键)

你们有什么建议?请忽略空的catch块,我已经对它们进行了测试并删除了它们的代码,以便在我为您发布的源代码中缩短内容。此外,这些语句是类的局部静态变量,我可以根据需要重用和重置它们

感谢您提供的任何意见。为了更好地了解我在做什么,我将发回您可能需要我透露的任何进一步细节


以下是一些我已经设法抓住的发现:

  • 由于我在TableView中显示行,所以我可以看到 数据库表中的值完全相同(I也相同) n记录它们),但主键(由自动生成)除外 SQLite整数自动增量)。。。所以这可能意味着 我的insert语句有问题,或者我发送 要插入的每一行的字典数据

  • 就JSON资源中的数据而言,根本没有问题 使用它,我捕获了整个字符串,将其缩进并显示 它需要验证信息的完整性以及所有匹配项 远程MySQL表

  • 在第一个代码块中,foreach循环读取:
    for(preguntas中的id pregunta){
    但是在中,您会发现他们使用
    for(id*item In items){
    (用*作为指针)。我尝试过将其设置为类似的,但我得到了一个错误,代码无论如何都不会编译

  • 是否有可能需要以某种方式重置传递给
    insertNewRecordIntoDatabase:
    函数的
    DSDictionary
    ,使其不包含以前的值?我假设每次迭代的数据都不同,但这证明我错了


以下是重复项的可能解释。请首先检查以下内容:

  • 您没有正确读取和显示记录
  • 插入记录时,插入两次。
    • (可能执行插入的函数会被多次调用。)
  • 服务器上的MySQL数据库有重复项
  • 您尚未删除原始记录。
    • (我想你排除了这个可能性。)
  • 希望这有帮助。干杯,

    Sascha

    我终于解决了这个问题。类的static
    insert\u语句
    变量(来自
    sqlite3\u stmt
    )导致了这个问题,因为当我从类声明中删除它们并在
    -(void)insertNewRecordIntoDatabase:(NSDictionary*)中创建/完成它们时pregunta_dict
    函数,然后所有插入都工作得很好。我现在在本地SQLite数据库中没有重复的行

    因此,吸取的教训是:至少对于
    INSERT
    语句,确保使用新的
    sqlite3\u stmt
    对象和
    sqlite3\u finalize()
    它们,而不是像我那样通过
    sqlite3\u reset()
    循环使用它们,否则您可能会在后续调用中插入相同的数据

    我还对整个类的insert函数做了一些更改,因为我现在将类的一个对象作为参数传递给它,并在插入时访问其属性以进行列匹配。下面是我的最终代码:

    - (void) insertInstanceIntoDatabase: (Pregunta *)pregunta database: (sqlite3 *)db {
        sqlite3_stmt *stmt_insert = nil;
        const char *sql = "INSERT INTO preguntas (id_pregunta, id_forma, numero, seccion, texto, respuesta, comentario, requiere_fotografia, fotografia, tipo) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
    
        if (sqlite3_prepare_v2(db, sql, -1, &stmt_insert, NULL) != SQLITE_OK) {
            NSAssert1(0, @"Error: Failed to prepare SQL statement: %s.", sqlite3_errmsg(db));
        } else {
            @try {
                sqlite3_bind_int (stmt_insert, 1,  pregunta.id_pregunta);
                sqlite3_bind_int (stmt_insert, 2,  pregunta.id_forma);
                sqlite3_bind_int (stmt_insert, 3,  pregunta.numero);
                sqlite3_bind_text(stmt_insert, 4, [pregunta.seccion             UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(stmt_insert, 5, [pregunta.texto               UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(stmt_insert, 6, [pregunta.respuesta           UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(stmt_insert, 7, [pregunta.comentario          UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(stmt_insert, 8, [pregunta.requiere_fotografia UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(stmt_insert, 9, [pregunta.fotografia          UTF8String], -1, SQLITE_TRANSIENT);
                sqlite3_bind_text(stmt_insert,10, [pregunta.tipo                UTF8String], -1, SQLITE_TRANSIENT);
            }
            @catch (NSException *exception) {
                ;
            }
        }
    
        if (sqlite3_step(stmt_insert) != SQLITE_DONE) {
            NSAssert1(0, @"Failed to prepare SQL statement: %s.", sqlite3_errmsg(db));
        }
    
        sqlite3_finalize(stmt_insert);
    }
    

    感谢您的反馈,Mundi,我更新了我的问题以反映进一步的发现。-也许主键可以帮助您。两个相同记录的主键是否相邻?表结构设置为自动添加主键,因为列是整数主键自动增量,我甚至不设置主键的列/value在插入新记录时…它们的插入由sqlite管理。