2010-02-26 23 views
5

Tôi muốn bao gồm cơ sở dữ liệu SQLite được cập nhật với phiên bản mới của ứng dụng. Ứng dụng của tôi sao chép tệp cơ sở dữ liệu vào thư mục Tài liệu khi khởi động. Cách tốt nhất để làm kiểu versioning này (ngoài việc sử dụng Core Data) là gì?SQLite, iPhone và versioning

Tôi giả định rằng một bảng 'phiên bản' đặc biệt trong tệp SQLite hoặc một tệp văn bản nhỏ với số phiên bản là cách để đi, nhưng tôi muốn nhận ý kiến ​​của người khác.

Trả lời

0

Sau khi thử một vài kỹ thuật, tôi đã kết thúc thêm một bảng cơ sở dữ liệu của tôi cho meta-thông tin và đưa vào một cột dấu thời gian. Mỗi khi tôi cập nhật ứng dụng của mình, tôi kiểm tra dấu thời gian của cơ sở dữ liệu gói dựa vào dấu thời gian của cơ sở dữ liệu đã sao chép (ví dụ: trong thư mục Tài liệu). Nó có nghĩa là tôi phải nhớ thay đổi giá trị dấu thời gian khi tôi cập nhật, nhưng nó đơn giản và nó hoạt động.

Sử dụng dấu thời gian tệp không hoạt động, vì có khả năng người dùng tải xuống ứng dụng trong cửa sổ Thời gian xem xét ứng dụng và kết thúc với cơ sở dữ liệu được sao chép bằng dấu thời gian mới hơn so với dấu thời gian trong gói.

0

Cách tôi làm điều này là bằng cách xem các cuộn phim. Nếu ngày sửa đổi của tệp SQLite DB trong gói .app gần đây hơn so với tệp trong thư mục tài liệu cục bộ, thì tôi sao chép tệp đó từ gói .app trên ... Đây là mã tôi sử dụng.

sqlite3 *dbh;   // Underlying database handle 
NSString *name;   // Database name (this is the basename part, without the extension) 
NSString *pathBundle; // Path to SQLite DB in the .app folder 
NSString *pathLocal; // Path to SQLite DB in the documents folder on the device 

- (BOOL)automaticallyCopyDatabase {        // Automatically copy DB from .app bundle to device document folder if needed 
    ES_CHECK(!dbh, NO, @"Can't autoCopy an already open DB") 
    ES_CHECK(name!=nil, NO, @"No DB name specified") 
    ES_CHECK(pathBundle!=nil, NO, @"No .app bundle path found, this is a cache DB") 
    ES_CHECK(pathLocal!=nil, NO, @"No local document path found, this is a read-only DB") 
    NSFileManager *fileManager = [NSFileManager defaultManager]; 
    NSDictionary *localAttr = [fileManager fileAttributesAtPath:pathLocal traverseLink:YES]; 
    BOOL needsCopy = NO; 
    if (localAttr == nil) { 
     needsCopy = YES; 
    } else { 
     NSDate *localDate; 
     NSDate *appDBDate; 
     if (localDate = [localAttr objectForKey:NSFileModificationDate]) { 
      ES_CHECK([fileManager fileExistsAtPath:pathBundle], NO, @"Internal error: file '%@' does not exist in .app bundle", pathBundle) 
      NSDictionary *appDBAttr = [fileManager fileAttributesAtPath:pathBundle traverseLink:YES]; 
      ES_CHECK(appDBAttr!=nil, NO, @"Internal error: can't get attributes for '%@'", pathBundle) 
      appDBDate = [appDBAttr objectForKey:NSFileModificationDate]; 
      ES_CHECK(appDBDate!=nil, NO, @"Internal error: can't get last modification date for '%@'", pathBundle) 
      needsCopy = [appDBDate compare:localDate] == NSOrderedDescending; 
     } else { 
      needsCopy = YES; 
     } 
    } 
    if (needsCopy) { 
     NSError *error; 
     BOOL success; 
     if (localAttr != nil) { 
      success = [fileManager removeItemAtPath:pathLocal error:&error]; 
      ES_CHECK(success, NO, @"Can't delete file '%@'" ,pathLocal) 
     } 
     success = [fileManager copyItemAtPath:pathBundle toPath:pathLocal error:&error]; 
     ES_CHECK(success, NO, @"Can't copy database '%@' to '%@': %@", pathBundle, pathLocal, [error localizedDescription]) 
     ES_TRACE(@"Copied DB '%@' to '%@'", pathBundle, pathLocal) 
     return success; 
    } 
    return YES; 
} 

Các ES_CHECK thứ chỉ là macro mà mở rộng ra không có gì trong chế độ phát hành, và nâng cao một ngoại lệ trong chế độ gỡ lỗi ... Họ trông như thế này:

#if ES_DEBUG 
#define ES_ASSERT(cond) assert(cond); 
#define ES_LOG(msg...) NSLog(msg); 
#define ES_TRACE(msg...) NSLog(msg); 
#else 
#define ES_ASSERT(cond) 
#define ES_LOG(msg...) 
#define ES_TRACE(msg...) 
#endif 
#define ES_CHECK(cond, ret, msg...) if (!(cond)) { ES_LOG(msg) ES_ASSERT(cond) return (ret); }  // Check with specified return value (when condition fails) 
+0

Macro 'ES_CHECK' là thú vị ... Trong chế độ gỡ lỗi, bạn thất bại với xác nhận, nhưng trong chế độ phát hành, bạn trả lại mã lỗi, vì vậy mã thực tế hoạt động cực kỳ khác nhau trong chế độ gỡ lỗi và phát hành. Vì vậy, bạn chỉ có thể kiểm tra xem mã gọi có thể xử lý mã lỗi được trả về bằng cách chuyển tất cả gỡ lỗi không? –

+0

Có. Nhưng không ai trong số các kiểm tra thất bại, đó là ý tưởng. Nếu họ đã từng thất bại trong sản xuất, họ cắt ngắn thường xuyên bằng cách trả lại một giá trị hợp lý thay vì bị rơi ... –

4

Không cần cho một bảng chuyên dụng. SQLite có một pragma cho điều này, được gọi là user_version. SQLite không sử dụng giá trị này cho bất cứ điều gì, nó hoàn toàn trái với ứng dụng.

Để đọc phiên bản:

#pragma user_version; 

Để cài đặt phiên bản:

#pragma user_version=1; 
+0

Làm thế nào để lập trình user_version trong sqlite? Tôi có thể đọc user_version từ db nhưng vì một số lý do cập nhật không thành công ... !! bất kỳ giúp đỡ? – Unicorn

+0

Đó là những gì xảy ra khi tôi làm việc từ bộ nhớ. :) Trả lời đã được sửa. –