2011-08-08 2 views
1

まず、私は似たような多くの質問を読んでいて、いくつかのアドバイスを受けて、私はstackoverflowユーザーに感謝します。JSONデータを使用してSQLiteから削除し、MySQLのリモートテーブルを同期させる

私はアプリケーションのiOS側でSQLiteに合計5つのデータベーステーブルを持ち、リモートサーバ用にMySQLで同等のデータベーステーブルを持っています。私はSQLiteのテーブルをプリロードしたデータを表示し、Appは期待通りに機能します。この問題は、iOSデバイスに保存されているローカル情報を置き換えるために、リモートデータベースからJSONデータをダウンロードするときに発生します。

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

そして最後に、これは関数でありますそれに渡された辞書オブジェクト使用して、データベースに新しいレコードを挿入します。今すぐ

- (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機能と関係があると思っていましたが、もう一度それは問題を引き起こすほど簡単すぎるようです。プライマリキーに格納する値を直接指定しようとしましたが、制約が満たされていないためにアプリケーションがクラッシュします(外部キーはなく、各テーブルのプライマリキーのみです)。

あなたはどのような提案をしていますか?空のキャッチブロックを無視して、それらをテストしてコードを削除しました。ここで、私があなたのために公開するソース内のものを短くすることができます。また、ステートメントは、必要に応じて再利用してリセットするクラスのローカル静的変数です。

入力いただきありがとうございます。私が何をしているのかをよりよく理解するために、私があなたに必要とするかもしれない詳細を公開する予定です。


ここで私がキャッチするために管理してきたいくつかの調査結果です:

  • 私はテーブルビュー内の行を表示しておりますので、私は、データベーステーブル内の すべての値があることがわかります( NSLogged)、プライマリキー( SQLite INTEGER AUTOINCREMENTによって自動生成されます)を除いて... が私の挿入ステートメントに間違っているか、または私がを送る方法を意味します挿入される各行の辞書データ。

  • 限り、私はそれをインデント、文字列全体をキャプチャし、 それを情報の完全な整合性を確認するために表示され、それはすべての に一致していることと、すべての で何も問題はありませんJSONリソースのデータとしてリモートのMySQLテーブルのものです。コードの最初のブロックで

  • 、foreachループを読み取りますfor (id pregunta in preguntas) {しかしthis articleであなたは、彼らが(ポインタのためのように*で)代わりにfor (id *item in items) {を使用しているでしょう。私はそれに似てしようとしたが、私はエラーが発生し、コードは何をコンパイルしません。

  • それは以前の値が含まれませんので、私は何とか私はinsertNewRecordIntoDatabase:関数に渡すDSDictionaryをリセットする必要があるだろうチャンスはありますか?私は、繰り返しごとにデータが異なると仮定しますが、これは私が間違っていることを証明しています。

答えて

1

私はついにこの問題を解決しました。クラスのstatic insert_statement変数(sqlite3_stmt)は、クラス宣言から削除し、- (void) insertNewRecordIntoDatabase:(NSDictionary *)pregunta_dictファンクション内でそれらを作成/最終化すると、すべての挿入が完全に機能するため、問題の原因となりました。私はローカルのSQLiteデータベースに重複する行がありません。

だから、レッスンは学んだ:INSERT文に対して少なくともそうでなければ、上に同じデータを挿入文で終わるかもしれない、あなたは代わりに私がやっていたようsqlite3_reset()を経由して、それらをリサイクルする新しいsqlite3_stmtオブジェクトとsqlite3_finalize()それらを、使用してくださいその後の呼び出し。

クラス全体の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); 
} 
1

重複の可能な説明は次のとおりです。これらを最初に確認してください:

  1. あなたは正しくレコードを読んで表示していません。
  2. レコードを挿入すると、2回挿入されます。
    • (挿入が複数回呼び出されるんたぶん機能。)
  3. サーバー上のMySQLデータベースには重複があります。
  4. 元のレコードを削除していません。
    • (私はあなたが1つのアウトという判決を下したと思います。)

は、この情報がお役に立てば幸いです。乾杯、
サスカ

+0

フィードバックMundiさん、私はさらなる発見を反映するために私の質問を更新しました。 –

+0

- プライマリキーが役立つかもしれません。 2つの同一レコードの主キーが隣接しているかどうか – Mundi

+0

列がINTEGER PRIMARY KEY AUTOINCREMENTであるため、テーブル構造はプライマリキーを自動的に追加するように設定されています。新しいレコードを挿入するときにプライマリキーの列/値を設定しない...挿入はsqliteによって管理されます。 –

関連する問題