Objective-C中ORM的运用:实体对象和字典的相互自动转换
http://blog.csdn.net/cooldragon/article/details/18991973
iOS开发中基于ORM的框架很多,如SQLitePersistentObject,实际开发中需求不同或场景不同,方式方法也就不同,有时项目中用不上ORM框架,或者出于公司或项目组习惯或规范、实际项目需求或技术要求等等原因,不会采用完整的ORM框架,但一些重复啰嗦的代码使用一定的ORM功能还是很能提高效率的。
基于性能或灵活性考虑,或复杂查询的需求,或项目组要求,项目中数据库存取一般直接用SQL或用FMDB的多些(某些产品研发型另说,软件架构设计是另一个话题,从笔者N年面试N多iOS开发者来看用FMDB的占了极大多数,不乏某某有名App),代码中使用字典、数组或自定义类(或叫实体)作为数据载体,FMDB的FMResultSet有个resultDictionary能够直接返回字典NSDictionary,再结合下面的辅助类,能够解决实体对象和字典(NSDictionary)的相互自动转换问题,不用一个Key一个Key,一个属性一个属性的自己去写代码了,避免重复手写烦杂和拼写错误的可能,大大的提高了开发效率。
- //
- // EntityHelper.h
- // 使用前提条件是:字典的Key和实体对象属性的单词是一样的,大小可以忽略。
- //
- // Created by LongJun on 13-1-28.
- // Copyright (c) 2013年 RL. All rights reserved.
- //
- #import <Foundation/Foundation.h>
- @interface EntityHelper : NSObject
- //字典对象转为实体对象
- + (void) dictionaryToEntity:(NSDictionary *)dict entity:(NSObject*)entity;
- //实体对象转为字典对象
- + (NSDictionary *) entityToDictionary:(id)entity;
- @end
- //
- // EntityHelper.m
- // ARProjectForPad
- //
- // Created by LongJun on 13-1-28.
- // Copyright (c) 2013年 RL. All rights reserved.
- //
- #import "EntityHelper.h"
- #import <objc/runtime.h>
- @implementation EntityHelper
- #pragma mark - Custom Method
- + (void) dictionaryToEntity:(NSDictionary *)dict entity:(NSObject*)entity
- {
- if (dict && entity) {
- for (NSString *keyName in [dict allKeys]) {
- //构建出属性的set方法
- NSString *destMethodName = [NSString stringWithFormat:@"set%@:",[keyName capitalizedString]]; //capitalizedString返回每个单词首字母大写的字符串(每个单词的其余字母转换为小写)
- SEL destMethodSelector = NSSelectorFromString(destMethodName);
- if ([entity respondsToSelector:destMethodSelector]) {
- [entity performSelector:destMethodSelector withObject:[dict objectForKey:keyName]];
- }
- }//end for
- }//end if
- }
- + (NSDictionary *) entityToDictionary:(id)entity
- {
- Class clazz = [entity class];
- u_int count;
- objc_property_t* properties = class_copyPropertyList(clazz, &count);
- NSMutableArray* propertyArray = [NSMutableArray arrayWithCapacity:count];
- NSMutableArray* valueArray = [NSMutableArray arrayWithCapacity:count];
- for (int i = 0; i < count ; i++)
- {
- objc_property_t prop=properties[i];
- const char* propertyName = property_getName(prop);
- [propertyArray addObject:[NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding]];
- // const char* attributeName = property_getAttributes(prop);
- // NSLog(@"%@",[NSString stringWithUTF8String:propertyName]);
- // NSLog(@"%@",[NSString stringWithUTF8String:attributeName]);
- id value = [entity performSelector:NSSelectorFromString([NSString stringWithUTF8String:propertyName])];
- if(value ==nil)
- [valueArray addObject:[NSNull null]];
- else {
- [valueArray addObject:value];
- }
- // NSLog(@"%@",value);
- }
- free(properties);
- NSDictionary* returnDic = [NSDictionary dictionaryWithObjects:valueArray forKeys:propertyArray];
- NSLog(@"%@", returnDic);
- return returnDic;
- }
- @end
实际使用(逻辑层)示例:
- //业务需要返回实体对象
- - (UserSCOInfoEntity*)loadStudyRecord:(UserSCOInfoQuery*)query
- {
- UserSCOInfoEntity *userSCOInfo = nil;
- @try {
- //
- NSDictionary *resultDict = [self loadStudyRecordForDict:query];
- if (!resultDict) return nil;
- //字典值自动填充到实体对象属性
- [EntityHelper dictionaryToEntity:resultDict entity:userSCOInfo];
- }
- @catch (NSException *exception) {
- NSAssert1(0, @"Exception=%@", exception.reason);
- }
- @finally {
- }
- return userSCOInfo;
- }
- //业务需要直接返回字典
- - (NSDictionary*)loadStudyRecordForDict:(UserSCOInfoQuery*)query
- {
- if (!query || !query.userID || !query.courseID || !query.scoID || !query.type || !query.typeID) {
- NSAssert(0, @"UserSCOInfoQuery对象或属性不能为空");
- return nil;
- }
- NSDictionary *resultDict = nil;
- FMDatabase *db = [FMDatabase databaseWithPath:[Common sharedInstance].localMainDb];
- @try {
- if (![db open]) {
- [db release];
- //NSLog(@"db open fail");
- return nil;
- }
- FMResultSet *s = [db executeQuery:@"SELECT … "];
- while ([s next]) {
- resultDict = [s resultDictionary];
- break;
- }
- [s close];
- if (!resultDict) {
- // NSString *errMsg = [db lastErrorMessage];
- //NSLog(@"[db lastErrorMessage]=%@",errMsg);
- }
- }
- @catch (NSException *exception) {
- NSAssert1(0, @"Exception=%@", exception.reason);
- }
- @finally {
- [db close];
- }
- return resultDict;
- }
当然,以上代码有一定应用场景,有一定的局限性,比如:
字典的Key和实体对象属性的单词必须是一样的(大小可以忽略),这里没有使用外部映射文件主要也是为了简化代码和项目的需要决定的。
Objective-C中ORM的运用:实体对象和字典的相互自动转换的更多相关文章
- Git.Framework 框架随手记--ORM查询返回实体对象
使用ORM有一个优势,可以通过某种机制将数据库中的数据转化为自己想要的对象形式数据.本章记录一下如何使用Git.Framework返回实体对象 一. Git.Framework 中提供的方法 在Git ...
- hibernate 实体对象的三种状态以及转换关系。
最新的Hibernate文档中为Hibernate对象定义了四种状态(原来是三种状态,面试的时候基本上问的也是三种状态),分别是:瞬时态(new, or transient).持久态(managed, ...
- EBS OAF开发中的Java 实体对象(Entity Object)验证功能补充
EBS OAF开发中的Java 实体对象(Entity Object)验证功能补充 (版权声明,本人原创或者翻译的文章如需转载,如转载用于个人学习,请注明出处:否则请与本人联系,违者必究) EO理论上 ...
- 静态方法中不能new内部类的实体对象
原因如下: 1.内部类可以访问外部类的成员变量 2.对象创建完成后对象的成员变量才会被分配空间 3.main的静态方法执行时可以不存在外部类,不创建实体对象 4.内部类能访问成员变量意味着一定存在外部 ...
- 项目中常用方法总结(将将DataTable数据集映射到实体对象)【转】
本篇把项目中用到的一些通用方法总结出来, 这些方法因为经常需要在项目中用到,所以把它们归纳在一起, 形成一个.dll 文件是一个理想的选择. 这样也便于日后缩短开发周期. 一. 把一个DataGrid ...
- 在实体对象中访问导航属性里的属性值出现异常“There is already an open DataReader associated with this Command which must be closed first”
在实体对象中访问导航属性里的属性值出现异常“There is already an open DataReader associated with this Command which must be ...
- CAD由一个自定义实体事件中的id得到自定义实体对象(com接口VB语言)
由一个自定义实体事件中的id得到自定义实体对象.该函数只能在自定义实体事件中调用. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 2 ...
- Hibernate中实体对象的状态
实体对象的状态 这里的实体对象是指Hibernate的O/R映射关系中的域对象(即O/R中的O).实体对象的生命周期是指实体对象由产生到被GC回收的一段过程,实体对象的生命周期包括3种状态:自由状态( ...
- EBS OAF开发中实体对象和视图对象的属性设置器
EBS OAF开发中实体对象和视图对象的属性设置器 (版权声明.本人原创或者翻译的文章如需转载,如转载用于个人学习,请注明出处:否则请与本人联系,违者必究) 源文: Home > Oracle ...
随机推荐
- BZOJ 4592 SHOI2015 脑洞治疗仪 线段树
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4592 题意概述:需要维护一个01序列A,一开始A全部都是1.支持如下操作: 1.将区间[l ...
- Spring Boot学习(二):配置文件
目录 前言 方式1:通过配置绑定对象的方式 方式2:@Value("${blog.author}")的形式获取属性值 相关说明 注解@Value的说明 参考 前言 Spring B ...
- PokeCats开发者日志(二)
现在是PokeCats游戏开发的第四天的上午,来记录一下昨天做的事情吧. day3 day3主要是添加音效和优化界面,本以为添加个音效1~2个小时就够了吧,没想到贼不顺,弄了一个下午才搞好. ...
- PAT 1084 外观数列
https://pintia.cn/problem-sets/994805260223102976/problems/994805260583813120 外观数列是指具有以下特点的整数序列: d, ...
- 【SSH】——spring的控制反转和依赖注入
spring是一个轻量级的容器框架,主要是为了使企业的开发变得简单.高效.无论是从大小还是开销来讲,他都可以算是轻量级的,也是非侵入性的. 下图是spring的框架示意图,说到spring,就不得不提 ...
- [剑指Offer] 34.第一个只出现一次的数
题目描述 在一个字符串(1<=字符串长度<=10000,全部由大写字母组成)中找到第一个只出现一次的字符,并返回它的位置 [思路]当一个字符第一次出现的位置和它最后一次出现的位置相同,那么 ...
- BZOJ4584 APIO2016赛艇(动态规划+组合数学)
如果值域不大,容易想到设f[i][j]为第i个学校选了j的方案数,枚举上一个学校是哪个选了啥即可,可以前缀和优化.于是考虑离散化,由于离散化后相同的数可能可以取不同的值,所以枚举第一个和其所选数(离散 ...
- [ZJOI2006]物流运输 DP 最短路
---题面--- 题解: 设f[i]表示到第i天的代价,cost[i][j]表示第i天到第j天采取同一种方案的最小代价.那么转移就很明显了,直接$n^2$枚举即可. 所以问题就变成了怎么获取cost数 ...
- Android 架构组件 Room 介绍及使用
关于Room Room是Google官方提供的数据库ORM框架,使用起来非常方便.Room在SQLite上提供了一个抽象层,以便在利用SQLite的全部功能的同时能更加流畅的访问数据库. Room中三 ...
- BZOJ2257 [Jsoi2009]瓶子和燃料 【裴蜀定理】
题目链接 BZOJ2257 题解 由裴蜀定理我们知道,若干的瓶子如此倾倒最小能凑出的是其\(gcd\) 现在我们需要求出\(n\)个瓶子中选出\(K\)个使\(gcd\)最大 每个数求出因数排序即可 ...