FMDB封裝,用OC方法存儲model,不用寫SQL語句。使用runtime獲取對象屬性

在實際開發中,數據庫存儲只會用到那幾個增刪改查SQL語句,不會用到多表查詢啊,多種條件增刪改啊。所以寫這個東西的目的,是把這幾個SQL語句封裝起來,在開發中操作數據庫就省去寫了SQL語句的麻煩。可能中間有些寫得不夠好,有興趣的大蝦過來指點指點小弟。


我們保存model,無非就是把所有的model裝到一個數據裏面,把數據直接塞進數據庫裏面即可。
創建SQL語句要得到model的鍵和值。這裏使用RunTime方法來獲取model的屬性。下面是核心代碼

    // model的屬性作爲表的列名
    // 可以通過RunTime的方法來獲取model的屬性

    // model屬性的個數
    unsigned int propertyCount = 0;

    // 通過運行時獲取model的屬性 這裏要導入 #import <objc/runtime.h>
    objc_property_t *propertys = class_copyPropertyList([model class], &propertyCount);

    for (int i = 0; i < propertyCount; i ++) {
        // 取出元素
        objc_property_t property = propertys[i];
        // 得到的是char*型的
        const char *propertyName = property_getName(property);
        // 轉化
        NSString *OCString = [NSString stringWithUTF8String:propertyName];
//        NSLog(@"%@", OCString);

操作數據庫分幾個步驟
1. 創建數據庫

……
#define  FMDBManager  [LJXFMDBManager ShareFMDBManager]
……

  // 一般保存到cache目錄裏面
    NSString *dataPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    dataPath = [dataPath stringByAppendingPathComponent:@"MyDB.sqlite"];
    // 創建數據庫
    [FMDBManager createDataBaseWithPath:dataPath];

爲了讓這過程中都能看到數據庫的東西,我們用SQLiteManager去下載SQLiteManager
打開數據庫文件,首先我們得找到這個文件。我在這文章裏有打開真機caches文件裏的方法。
http://blog.csdn.net/u010971348/article/details/53290523

打開caches目錄後,可以看到創建的sqlite文件,安裝了SQLiteManager的話,默認打開方式就是SQLiteManager了。又擊它,沒創表的時候,當然是空的,我這裏創建了表,

創建表代碼, 爲了方便操作,傳一個主鍵過去。(不設置主鍵的我也寫過了,結果,操作麻煩,比如插入會有重複的model,要解決這個問題,就要在插入之前查一下表,看要插入的model存不存在,存在的話就替換,不存在的話就插入,這樣子太浪更內存了)

調用方法
    NSString *tableName =_tableName.text;
    Class modelClass = [CheckinModel class];
    if ([FMDBManager createTableWithName:tableName model:modelClass primaryKey:@"flightCode"]) {
      [self showMessage:@"創表成功"];
    } else {
        [self showMessage:@"創表失敗"];
    }

/**
 創建表

 @param tableName 表名
 @param primaryKey 設置主鍵以便操作
 @return 創建表是否成功
 */
- (BOOL)createTableWithName:(NSString *)tableName model:(Class)model primaryKey:(NSString *)primaryKey;


- (BOOL)createTableWithName:(NSString *)tableName model:(Class)model primaryKey:(NSString *)primaryKey
{
    if (self.dataBase) {
        // 打開數據庫
        [self.dataBase open];
        // 判斷表是否存在
        BOOL success = [self.dataBase tableExists:tableName];

        if (success) {
            // 存在就不用創建了,操作完成。記得關閉數據庫
            [self.dataBase close];
            return YES;
        } else {
            // 不存在的話,
            // 創建SQL語句;
            NSString *SQLString = [self createTableSQLString:model tableName:tableName primaryKey:primaryKey];
            if ([self.dataBase executeUpdate:SQLString]) {
                // 創建表成功,關閉
                [self.dataBase close];
                return YES;
            } else {
                return NO;
            }
        }
    } else {
        NSLog(@"數據庫不存在");
        return NO;
    }
}

// 創表語句
- (NSString *)createTableSQLString:(id)model tableName:(NSString *)tableName primaryKey:(NSString *)primaryKey
{
    // 爲了提交表數據的容錯性,都用text 類型
    NSString *sqliteString = [NSString stringWithFormat:@"create table if not exists %@ (%@ text primary key", tableName, primaryKey];

    // model的屬性作爲表的列名
    // 可以通過RunTime的方法來獲取model的屬性

    // model屬性的個數
    unsigned int propertyCount = 0;

    // 通過運行時獲取model的屬性 這裏要導入 #import <objc/runtime.h>
    objc_property_t *propertys = class_copyPropertyList([model class], &propertyCount);

    for (int i = 0; i < propertyCount; i ++) {
        // 取出元素
        objc_property_t property = propertys[i];
        // 得到的是char*型的
        const char *propertyName = property_getName(property);
        // 轉化
        NSString *OCString = [NSString stringWithUTF8String:propertyName];
//        NSLog(@"%@", OCString);
        // 如果是主鍵的話,就不用拼接上去了,因爲一開始就拼了
        if (![OCString isEqualToString:primaryKey]) {
            // 拼接
            if (i == 0) {
                sqliteString = [sqliteString stringByAppendingString:[NSString stringWithFormat:@"%@ text", OCString]];
            } else {
                sqliteString = [sqliteString stringByAppendingString:[NSString stringWithFormat:@", %@ text", OCString]];
            }
        }

    }
    sqliteString = [sqliteString stringByAppendingString:@")"];

    return sqliteString;
}

創建表成功後,我們可以在那個sqlite文件裏面看到這些東西,可以看到,表的列名就是model的屬性名,除了前面的那個rowid是自己本來就有的

接下來就是插入model了。

  NSMutableArray *muta = [NSMutableArray array];
    NSString *path = [[NSBundle mainBundle] pathForResource:@"checkin" ofType:@"json"];
    NSData *jsData = [NSData dataWithContentsOfFile:path];
    NSDictionary *dataDic = [NSJSONSerialization JSONObjectWithData:jsData options:NSJSONReadingMutableContainers error:nil];
    NSArray *dataArray = dataDic[@"data"];
    for (NSDictionary *subDic in dataArray) {
        CheckinModel *model = [CheckinModel initWithDic:subDic];
        [muta addObject:model];
    }
    /// 插入
    if ([FMDBManager insterModelArray:muta toTable:_tableName.text]) {
        [self showMessage:@"插入成功"];
        NSArray *all = [FMDBManager searchAllModel:[CheckinModel class] tableName:_tableName.text];
        [_dataArray removeAllObjects];
        [_dataArray addObjectsFromArray:all];
        [self.tableView reloadData];
        NSLog(@"個數%ld", all.count);
    } else {
        [self showMessage:@"插入失敗"];
    }

/**
  插入 模型 數組

 @param modelArray 模型數組
 @param tableName 表名
 @return 插入是否成功
 */
 .h裏面
- (BOOL)insterModelArray:(NSArray *)modelArray toTable:(NSString *)tableName;

.m裏面
// 插入一組
- (BOOL)insterModelArray:(NSArray *)modelArray toTable:(NSString *)tableName
{
    if (self.dataBase) {
        // 凡事先打開數據庫
        [self.dataBase open];

        if ([self.dataBase tableExists:tableName]) {
            NSString *sqlString = @"";
            for (NSInteger i = 0; i < modelArray.count; i ++) {
                // 拼接sql語句
                NSString *subString = [self insertSQLStringWith:modelArray[i] tableName:tableName];
                if (i == 0) {
                    sqlString = [sqlString stringByAppendingString:subString];
                } else {
                    sqlString = [sqlString stringByAppendingFormat:@"; %@", subString];
                }
            }

            // 多行執行
            BOOL success = [self.dataBase executeStatements:sqlString];
            [self.dataBase close];
            return success;
        }else {
            // 表不存在
            NSLog(@"插入失敗,表不存在");
            [self.dataBase close];
            return NO;
        }
    } else {
        // 數據庫都不存在,先去創建數據庫吧
        NSLog(@"數據庫不存在");
        return NO;
    }
}

// 插入數據語句
- (NSString *)insertSQLStringWith:(id)model tableName:(NSString *)tableName
{
    NSString *sqliteString = [NSString stringWithFormat:@"insert or replace into %@ (", tableName];
    // 一般是以model的屬性作爲表的列名
    // 可以通過RunTime的方法來獲取model的屬性

    // model屬性的個數
    unsigned int propertyCount = 0;

    // 通過運行時獲取model的屬性 這裏要導入 #import <objc/runtime.h>
    objc_property_t *propertys = class_copyPropertyList([model class], &propertyCount);
    // 裝屬性的數組
    NSMutableArray *keyArray = [NSMutableArray array];
    for (int i = 0; i < propertyCount; i ++) {
        // 取出元素
        objc_property_t property = propertys[i];
        const char *propertyName = property_getName(property);
        // 轉化
        NSString *OCString = [NSString stringWithUTF8String:propertyName];

        NSString *valueString = [NSString stringWithFormat:@"%@",[model valueForKey:OCString]];
        if (valueString.length > 0) {
            // 如果model的屬性沒有值的話,那就不加操作那列值了
            // 保存鍵
            [keyArray addObject:OCString];
            // 拼接
            if (i == 0) {
                sqliteString = [sqliteString stringByAppendingString:[NSString stringWithFormat:@"'%@'",OCString]];
            } else {
                sqliteString = [sqliteString stringByAppendingString:[NSString stringWithFormat:@", '%@'", OCString]];
            }
        }
    }
    sqliteString = [sqliteString stringByAppendingString:@") values ("];

    // 值
    for (int i = 0; i < keyArray.count; i ++) {
        NSString *key = keyArray[i];
        NSString *keyString;
        // 拼接 記得加單引號
        if (i == 0) {
            keyString = [NSString stringWithFormat:@"'%@'", [model valueForKey:key]];
        } else {
              keyString = [NSString stringWithFormat:@", '%@'", [model valueForKey:key]];
        }

        sqliteString = [sqliteString stringByAppendingString:keyString];
    }
    //
    sqliteString = [sqliteString stringByAppendingString:@")"];
    return sqliteString;
}

執行完後,再看看sqlite裏面

用得最多的就是這個插入方法了,因爲他也是更新方法,你隨便插入model,不過要是那一類model,如果裏面有相同的話,他會直接替換掉,我這裏用的SQL語句是
insert or replace into 避免他有重複的model。
還有更他的方法

**
 查詢某條數據所在的model。比如學號(key)爲2001(vlaue)的model

 @param model 所查model類型
 @param keyString 所查的鍵
 @param valueString 所查的值
 @param tableName 所查的表
 @return 返回的model數組
 */
- (NSArray *)searchModel:(Class)model WithKey:(NSString *)keyString value:(NSString *)valueString inTable:(NSString *)tableName;

/**
 查詢所有的model

 @param modelClass 所查的model類型
 @param tableName 表名
 @return 所有的model
 */
- (NSArray *)searchAllModel:(Class)modelClass tableName:(NSString *)tableName;


#pragma mark - 刪除

/**
 刪除表中所有的數據, 不刪除表, 但不刪除列名

 @param tableName 表名
 @return 是否刪除成功
 */
- (BOOL)truncateTable:(NSString *)tableName;

/**
 刪除整個表

 @param tableName 表名
 @return 是否刪除成功
 */
- (BOOL)dropTable:(NSString *)tableName;


/**
 刪除指定條件的model
 如:刪除學號 爲 2002的model
 @param columnName 指定列名
 @param columnValue 指定列值
 @param tableName 表名
 @return 刪除成功與否
 */
- (BOOL)deleteModelColumnName:(NSString *)columnName columnValue:(NSString *)columnValue tableName:(NSString *)tableName;

都寫進去了,demo請移步gitHub

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章