最近整了个BookRent的小应用,单机版、连本地sqlite db、wpf界面,其中涉及到一些有趣的小功能和小坑,简单小结一下。
项目结构是wpf ui->view model->repository->sqlite db,各层间用接口隔开,写在1个项目里,拆起来也方便。
1. DataRepository层的Cache
在数据存取层封了个Cache,只在这一层内部使用,外部不知道Cache的存在。可以改进的地方有:
- repository的代码比较相似,可以引入T4等模板工具
- query里的getCache、add/delete/update里的setCache可以引入entlib等工具里的aop
- 如果逻辑简单,直接用template;复杂一些就用aop。目前的场景下template够用了
- 对db和cache的操作应该封到1个transaction里,否则出错了就不一致了
- 目前queryCondition是查出所有后,再在内存里过滤。数据量大一些之后,可以考虑引入EF.sqlite之类的ORM工具
- 目前不支持启动时创建db、验证db等,也可以考虑扔给orm去做
- 删除列: sqlite默认不支持删除列,所以只能建临时表、拷贝数据、再重命名。详情见这个stackoverflow的帖子。
2. Model层
Model层虽然简单,但也有些小坑:
- 原以为ISBN是唯一的,结果一查,ISBN与书(特别是系列书)之间完全是多对多的关系,根本就是一团乱麻,据说是取决于各出版社的喜好。所以,主键采用sqlite默认自增长的rowid,对象的equality比较也用rowid。
- 注意enum里要用
enum Types { Type0 = 0, Type1 = 1 }
的形式,不然以后enum里换顺序就坑了
3. ViewModel层
- 这里会听一些插件的消息,注意Timer或ThreadPool里发消息的不是ui线程,要扔给Dispatcher由它排入ui线程的队列里等待处理
- 还会听其他ViewModel的消息,同步更新Model的状态,用户不需要反复点查询
4. View层
- 新增/编辑时采用无弹框的设计,改了就直接保存,大量录入时会很方便。
- 没做启动闪屏、没做菜单的动态加载,启动时加载所有(3个)页面,会有卡顿感,页面多了要改为动态加载,配合unity之类的。
- 所有按钮都绑定快捷键,可全键盘操作,但没做成可配置的。
5. 插件Plugins
- 所有插件都读取app.config的配置,并设置timer定时执行。为方便可读,很多config项和enum都直接用中文。
- IsbnPlugin的功能比较有趣,可根据isbn访问豆瓣rest api获取书名、价格、作者、出版社等信息。这个插件配合扫描枪录入isbn,录几百本书都轻松愉快。甚至可以批量导入isbn号。为了减少server的压力,豆瓣限制每分钟每IP访问次数约为2.5次。为防止被封IP,限制程序每30秒访问一次。
- sqlite db是本地文件,因此要做本地备份。如果能联网的话,还可以配合baidu云盘的api备份到云端。
- 嘲讽的是,做完才知道,用户没法联网。只能呵呵了。
6. 其他
- 还有1个有趣的点是用户希望输入拼音首字母快速检索。原以为要用什么算法,百思不得其解。结果一搜索,擦,全是穷举映射。想想也对,中文字形和拼音之间确实没什么关系。比较了一下,选用园子里kingboy2008的这篇,特此表示感谢!简单的实现,多半是不支持多音字的。要支持多音字,又要继续穷举了。实现之间的差别,只在准确度、内存消耗、查找速度上。
基本就这些,后续可以考虑转成b/s+mobile上,练手呗。
作者:AlexanderYao
出处:http://alexanderyao.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。