• Stars
    star
    506
  • Rank 87,236 (Top 2 %)
  • Language
    Objective-C
  • License
    MIT License
  • Created over 8 years ago
  • Updated almost 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

iOS用对FMDB封装

一个对FMDB进行类Hibernate封装的ios库

Build Status Pod Version Pod Platform Pod License

GitHub: sucbers

Feedback: [email protected]

有问题或者bug欢迎随时issues我,或者邮件。感谢使用

2.0更新

  • 数据库字段名,从默认的_ivar名 改为 property名 : _name -> name
  • 数据库操作对象获取改为连接池: [JRDBMgr defaultDB] -> [JRDBMgr shareInstance].getHandler
  • 抛弃缓存功能
  • 新增And, Or查询语句

描述(Description)

  • 使用分类的模式,模仿Hibernate,对FMDB进行简易封装
  • 使用协议,不用继承基类,对任意NSObject可以进行入库操作
  • Objective-C(Swift 请移步 Swift扩展

目录(Index)

安装(Installation)

pod 'JRDB'

开始(Start)

JRDBMgr 使用

设置数据库路径

[[JRDBMgr shareInstance] setDefaultDatabasePath:@"/Users/mac/Desktop/test11.sqlite"];

是否打印sql语句

[JRDBMgr shareInstance].debugMode = YES;

获取处理器

  • 从连接池中获取数据库处理器
[[JRDBMgr shareInstance] getHandler]; 

关闭数据库

[[JRDBMgr shareInstance] close]; 

注册

  • 需要使用本库的类都需要注册。
[[JRDBMgr shareInstance] registerClazzes:@[
                                           [Person class],
                                           ]];

表名

默认类名为表明,可以自定义表名,在主类中重写一下方法即可

+ (NSString *)jr_customTableName {
    return @"my_tableName";
}

主键

默认每个对象入库都会持有一个ID [person ID] , 作为数据库的主键,库通过这个 ID 来识别对象是否与数据库关联,所以不是必要时,不要操作此属性

自定义主键

不同的业务需求,有可能使用的主键有特定的业务意义,需要自行定义。

在需要自定义的实体类中实现一下方法

/// 自定义主键的对应的属性 (需要是属性的全名)
+ (NSString *)jr_customPrimarykey {
    return @"name"; // 对应property的属性名
}
/// 自定义主键属性值
- (id)jr_customPrimarykeyValue {
    return self.name;
}

通过下面的方法可以获取对应的值

/**
 *  如果有自定义主键,则返回自定义主键key,例如 name,若没有实现,则返回默认主键key : @"_ID"
 */
[Person jr_primaryKey];

/**
 * 如果有自定义主键,则返回自定义主键的值,如果没有,则返回 [self ID]
 */
[p jr_primaryKeyValue];

自定义字段名

默认使用Property的属性名进行字段名定义,可以对每个地段进行自定义数据库字段名,在主类中重写以下方法即可

  • 无返回字段默认使用property属性名当做数据库列名
+ (NSDictionary<NSString *,NSString *> *)jr_databaseNameMap {
    return @{
             @"name" : @"db_name",
             @"age" : @"db_age",
             @"height" : @"db_height",
             };
}

忽略字段

默认非数据库基本类型都会忽略不入库。

数据库基本类型:

  • NSString
  • NSDate
  • NSData
  • int, unsigned int, double, float, long.....

非以上类型都会自动忽略不入库。

若有特定需要忽略字段,需要实现一下方法

/// 忽略age属性,不做入库操作
+ (NSArray *)jr_excludePropertyNames {
    return @[
             @"age",
             ];
}

表操作(TableOperation)

建表

J_CreateTable(Person)

更新表

  • 更新表时只会添加字段,不会删除或更新字段名,有需要的话需要自行写sql语句解决

J_UpdateTable(Person)

删除表

J_DropTable(Person)

重建表

J_TruncateTable(Person)


保存(Save)

    
BOOL result = J_Insert(p)
					.InDB([JRDBMgr shareInstance].getHandler) // by Default
					.Recursive(NO)  		       // by default
					.Sync(YES)			       // by default
					.Transaction(YES)	       // by default
					.updateResult;             // 执行
    
// 可以省略为
BOOL result = J_Insert(p).updateResult;
    
// 数组保存,两种 api 自由使用
BOOL result = J_Insert(p1, p2, p3).updateResult;
    
BOOL result = J_Insert(@[p1, p2, p3]).updateResult;

更新 (Update)

更新操作需要提供对象的主键,请确保需要更新的对象都是从数据库查出来的;(也可以手动设置主键让库识别,不建议)

BOOL result = J_Update(p)
					.Columns(@[@"age", @"name"])  // 更新指定列
				//	.Ignore(@[@"age", @"name"])   // 忽略指定列
					.InDB([JRDBMgr shareInstance].getHandler)      // by default
					.Recursive(NO)                  // by default
					.Sync(YES)                      // by default
					.Transaction(YES)               // by default
					.updateResult;                  // 执行
					
BOOL result = J_Update(p).Ignore(@[@"phone"]).updateResult;

// 更新数组
BOOL result = J_Update(p1, p2).updateResult;
BOOL result = J_Update(@[p1, p2, p3]).updateResult;

删除(Delete)

删除操作需要提供对象的主键,请确保需要更新的对象都是从数据库查出来的;(也可以手动设置主键让库识别,不建议)

// 删除
BOOL result = J_Delete(p)
					.InDB([JRDBMgr shareInstance].getHandler)      // by default
					.Recursive(NO)                  // by default
					.Sync(YES)                      // by default
					.Transaction(YES)               // by default
					.updateResult;                  // 执行

查询(Query)

// 条件查询

// And Or 对应Property中的属性名

NSArray<Person *> = J_Select(Person) // select * from person [where 1=1]
						.And(@"age").lt(@10) // and age < 10
						.Or(@"height").gt(@120) // or height > 120
						.Or(@"name").like(@"Wang%") // or name like 'Wang%'
						.And(@"weight").nq(@200) // and weight <> 200
						.list

// 普通查询
NSArray<Person *> *result =
				    J_Select(Person)    // 指定查询对象
				    .Recursive(YES)		// 默认 可省略
				    .Sync(YES)			// 默认 可省略
				    .Desc(NO)           // 默认 可省略
				    .Where(@"name like ? and height > ?")  // 对应数据库中的字段名
				    .Params(@[@"L%", @150])                // 对应条件语句的 ? 可省略
				    .Group(@"level")                      // Group 可省略
				    .Order(@"age")                        // Order 可省略
				    .Limit(0, 10)                          // 分页 start, length 可省略
				    .list;

// 自定义查询
NSArray<Person *> *result1 =
						J_SelectColumns(@[@"age", @"name"])
						.From([Person class])
						.Recursive(YES)   // 在自定义查询中不会起作用
						.Sync(YES)		  //  默认 可省略
						.Where(@"name like ? and height > ?") // 对应数据库中的字段名
						.Params(@[@"L%", @150])
						.Group(@"level") // 对应数据库中的字段名
						.Order(@"age") // 对应数据库中的字段名
						.Limit(0, 10)
						.Desc(NO)
						.list;

NSUInteger count =
				J_SelectCount(Person) // 查询哪个类
				.Recursive(YES)   // 在自定义查询中不会起作用
				.Sync(YES)		  //  默认 可省略
				.Where(@"name like ? and height > ?")
				.Params(@[@"L%", @150])
				.Group(@"level")
				.Order(@"age")
				.Limit(0, 10)
				.Desc(NO)
				.count;
                    

链式调用配置(Configuration)

配置 功能 参数类型
InDB [JRDBMgr shareInstance].getHandler by default; id<JRPersistentHandler>
From 自定义查询时指定的类名
or 子查询的Chain对象
Class | JRDBChain *
Recursive NO by default;
NO:效率高,
YES:关联操作效率低
YES or NO
Transaction YES by default;
NO:本操作不包含事务,外界需要事务支持
YES:包含事务
YES or NO
Sync YES by default;
YES:阻塞本线程,线程安全同步执行数据库操作;
NO:在本线程执行数据库操作,线程不安全
YES or NO
Where Where 后面的条件筛选语句,使用 ?作为参数占位符
使用的字段需要与数据库字段相同
NSString *
WhereIdIs 等同于 Where(@" _id = ?") NSString *
WherePKIs 等同于 Where(@"<#primary key#> = ?") id
And And语句,跟着属性名 And(@"name") NSString
Or Or语句,跟着属性名 Or(@"age") NSString
eq eq语句,跟着参数 eq(@10) 相当于SQL语句的 「=」 id
nq nq语句,跟着参数 nq(@10) 相当于SQL语句的 「<>」 id
gt gt语句,跟着参数 eq(@10) 相当于SQL语句的 「>」 id
lt lt语句,跟着参数 eq(@10) 相当于SQL语句的 「<」 id
gtOrEq gtOrEq语句,跟着参数 eq(@10) 相当于SQL语句的 「>=」 id
ltOrEq ltOrEq语句,跟着参数 eq(@10) 相当于SQL语句的 「<=」 id
like like语句,跟着参数 eq(@10) 相当于SQL语句的 「like」 id
Params Where 语句占位符对应的参数 NSArray *
Columns 更新时候指定更新的列 NSArray *
Ignore 更新时指定忽略的列 NSArray *
Group group by 字段 NSString *
Order order by 字段 NSString *
Limit 分页字段 (start, length) unsigned long, unsigned long
Desc NO by default; 是否根据orderby 进行降序 YES or NO

关联操作(Link)

描述:当一个类的一个属性为一个实体类,在操作数据库时,通过配置,也可以进行同时操作

例如:当保存 Person 时,也想同时保存 card 对象, Money数组,以及 children数组, 则可以进行关联操作。需要在对应的类实现一下方法, 并且子对象也需要注册

// 注册子model类 
[[JRDBMgr shareInstance] registerClazzes:@[
                                           [Person class],
                                           [Card class],
                                           [Money class],
                                           ]];



@interface Person : NSObject

@property (nonatomic, strong) Card *card;
@property (nonatomic, strong) NSMutableArray<Money *> *money;
@property (nonatomic, strong) NSMutableArray<Person *> *children;

@end

@implementation

/// 单个对象关联
+ (NSDictionary<NSString *,Class<JRPersistent>> *)jr_singleLinkedPropertyNames {
    return @{
             @"card" : [Card class],
             };
}

/// 数组对象关联
+ (NSDictionary<NSString *,Class<JRPersistent>> *)jr_oneToManyLinkedPropertyNames {
    return @{
             @"money" : [Money class],
             @"children" : [Person class],
             };
}

@end

关联操作 (保存)

Person *p = [Person new];
Card *c = [Card new];
p.card = c;
p.money = @[m1,m2,m3];
p.children = @[p1,p2,p3];

BOOL result = J_Insert(p)
					.Recursive(YES) // 默认为NO, 需要手动指定关联保存
					.updateResult;

关联操作(更新)

注意:若子对象都是没有保存过的(既数据库没有的对象),则全部保存。若有已存在对象,不保存不更新。

  • 出于更新的操作的随意性比较重,更新时不进行一切关联操作,即更新时,只更新本model相关信息,不更新所有子model的信息。当层级较多的时候,需要从子层级开始一步一步开始更新上来(所以不建议建立太多层级)

  • 更新本model的信息包括:

    • 子model的ID会保存(若有)
    • 子model数组的数量(若子model数组数量发生变更会更新,但是子model的数组不会更到数据库)
BOOL result = J_Update(p).Recursive(YES).updateResult;

--

关联操作(删除)

  • 和更新一样,删除时,只会删除本model的信息,不会进行一切关联操作。
  • 删除时,会删除一对多的中间表无用信息
BOOL result = J_Delete(p).Recursive(YES).updateResult;

关联操作(查询)

NSArray<Person *> *list = J_Select(Person).Recursive(YES).list;

宏(Macro)

  • 使用宏,让调用变成更智能
    • From([Person class]) --> FromJ(Person)
    • Where(@"name = ?") --> WhereJ(_name = ?)
    • Order(@"name") --> OrderJ(name)
    • Group(@"name") --> GroupJ(name)
    • Params(@[@"jack", @"mark"]) --> ParamsJ(@"jack", @"mark")
    • Ignore(@[@"name", @"age"]) --> IgnoreJ(@"name", @"age")
    • Columns(@[@"name", @"age"]) --> ColumnsJ(@"name", @"age")
// example
NSArray *result = J_Select(Person)
                    .WhereJ(name like ? and height > ?)
                    .ParamsJ(@"a%", @100)
                    .GroupJ(h_double)
                    .OrderJ(d_long_long)
                    .list;
                    
BOOL result = J_Update(person)
						.ColumnsJ(J(name), J(age))
					//	.IgnoreJ(J(name), J(age))
                    .updateResult;

子查询(SubQuery)

// 正常查询只能先排序再分页,加入子查询,可以先分页,再从子结果中排序 . ie. 

NSArray<Person *> *list =J_Select(Person)
                                .From(
                                    J_Select(Person).Limit(0, 10) // 放入一个子查询,外部查询则从子查询的结果里继续查询
                                ).OrderJ(age)
                                .Descend
                                .list;

NSObject+JRDB

给NSObject添加分类方法,以方便快捷的方式使用本库的渐变功能

- (BOOL)jr_saveOrUpdateOnly;// 非关联操作
- (BOOL)jr_saveOrUpdate;	 // 关联操作

#pragma mark - save

- (BOOL)jr_saveOnly;
- (BOOL)jr_save;

#pragma mark - update

- (BOOL)jr_updateOnlyColumns:(NSArray<NSString *> * _Nullable)columns;
- (BOOL)jr_updateColumns:(NSArray<NSString *> * _Nullable)columns;

- (BOOL)jr_updateOnlyIgnore:(NSArray<NSString *> * _Nullable)Ignore;
- (BOOL)jr_updateIgnore:(NSArray<NSString *> * _Nullable)Ignore;

#pragma mark - delete

+ (BOOL)jr_deleteAllOnly;
+ (BOOL)jr_deleteAll;

- (BOOL)jr_deleteOnly;
- (BOOL)jr_delete;

#pragma mark - select

/// 关联查询
+ (instancetype _Nullable)jr_findByID:(NSString * _Nonnull)ID;
+ (instancetype _Nullable)jr_findByPrimaryKey:(id _Nonnull)primaryKey;
+ (NSArray<id<JRPersistent>> * _Nonnull)jr_findAll;

/// 非关联查询
+ (instancetype _Nullable)jr_getByID:(NSString * _Nonnull)ID;
+ (instancetype _Nullable)jr_getByPrimaryKey:(id _Nonnull)primaryKey;
+ (NSArray<id<JRPersistent>> * _Nonnull)jr_getAll;

线程安全

使用本库的数据库,都是阻塞本线程,并且线程安全的,所有操作带有事务。
操作本库管理的数据库时,请使用本库提供的API进行操作,否则有可能产生数据库锁问题


泛型提示

abc

通过泛型,查询出来后,编译器直接识别结果为对应对象,减少强转操作。


更多使用 请查看 JRPersistentHandler.h