从零开始用C#做产品:私人日记(15)分类界面与数据库联动

上一节我们对DBController进行了封装,这节需要对它进行调用,让分类界面与数据库能够联动起来。

在设计DBController时候,其实是有两种方案的:

一是短连接。每次访问数据库先创建一个连接,然后执行sql语句,再关闭数据库连接。这种在多线程或多进程中,可以明显减少sqlite的最大连接数。显而易见,由于需要每次都调用打开关闭数据库,效率较低,尤其是需要频繁进行sql操作时会更加明显。

二是长连接。程序初始化时打开数据库,直到程序关闭再关闭数据库,程序的对数据库的所有操作都通过这个连接来进行。这种可以提升效率,但是如果有多线程或其他进程也都是一直保持连接,会不会有问题呢?应该这样说,所有数据库都有最大连接数,但是Sqlite的并发处理比较弱,一个线程在写的时候,其他所有连接都要被锁,这就导致了sqlite在并发时效率会非常低。换句话说,由于sqlite的并发瓶颈,导致它根本等不到连接数量限制,自己就先崩溃了。

我们之所以选择第二种方案,就是因为我们的项目只是一个单机版软件,不牵涉到并发,不需要考虑,还考虑连接数做什么呢?

既然是第二种方案,那必然不需要每次使用DBController都进行实例化,因为一旦对DBController实例化就需要再次连接数据库,与我们的设计初衷不符。

那是不是说我们可以把DBController声明为一个静态类就可以了呢?我认为不好,因为如果你声明的是一个静态类,一个程序就只能打开一个实例,如果只考虑单库操作,倒是也问题不大。但是我们不能保证未来会增加哪些功能,比如我们要增加多库操作的功能,需要在不同数据库之间传输数据,如果用静态类就没办法做到了。

我们期望的是大多数情况下,我们就用一个默认的DBController实例来操作数据库,如果需要操作多个数据库,那再新创建DBController实例就好。

比较容易理解的方式是:我们先声明一个全局变量的实例,程序默认使用就用它,如果以后有需要其他的实例就再额外创建。但是这个全局变量放在哪儿呢?如果在BAL类库中额外声明一个全局类,那就等于说为了用这一个DBController,我们还需要再声明一个全局类中,这在类的设计上不够流畅,因为你这样会导致你的代码中,要想使用这个实例,就得先找到对应的全局类,如果有多个类似的情况,就要声明多个全局的类,使用起来比较混乱。

最优雅的方式是把这个全局变量放到DBController类中,也就是DBController类里面再声明一个自身的DBController的静态实例。这样以后要使用DBController中直接通过DBController就能找到这个静态实例,想要再实例化一个新的对象也没有问题。在DBController类中,我们加入如下内容:

static DBController _DefaultInstance = null;
public static DBController Default
{
get
{
if (_DefaultInstance == null)
{
_DefaultInstance = new DBController();
}
return _DefaultInstance;
}
}

在DBController类中声明一个该类的静态私有实例_DefaultInstance,然后再声明一个只读的公有属性Default,如果_DefaultInstance为空就创建新的实例,如果不为空就返回。这样在程序的任何位置使用DBController.Default,都像是使用全局变量一样,可以保证它的唯一性。如果用DBController创建一个新的实例,跟Default是两个完全不同的实例,毫无影响,非常的优雅。

上面的这种其实不是我独创的,而是在软件设计模式中,被称为单体模式(也有叫单键模式的),单体模式只是其中的一个比较简单的设计思想。设计模式也是推荐同学们看的一本书,里面总结了很多软件设计思想,可以说市面上绝大多数软件设计思想无出其右,其地位不亚于金庸笔下的天下武学总纲《九阴真经》。可惜我也只是理解了其中的一点皮毛,到后面那些模式我也都看不大懂了,有天赋的同学可以趁年轻多了解一些,保证受用无穷。里面的思想不仅可以用于软件设计,也可以用于现实世界中归纳各种事物的方法、总结其规律,更有利于理解事物的本质。所谓的格物致知,也便是如此吧。

上面10几行代码我又说了很多,我想看过我之前的教程的同学们应该也都有了解了吧。虽然我这写的是C#入门教程,但我不会只介绍C#的语法,我觉得这些纯技术的东西你到网上查就好了,遇到什么问题就查什么问题,非常精准,比在头条上看高效多了。我这里重点还是讲为什么要这样做、有什么好处,不这样做以后会有什么样的潜在风险。我看过的一些教程,基本都是介绍各种新的技术、新的框架、新的工具,都是纯技术的内容,跟着学貌似可以快速做出一些东西来,但做完后你未必了解它的本质,你只是学到了一点皮毛而已。真正到你自己做产品的时候你会发现,你学的那些皮毛基本没什么用,因为自己做产品绝大多数功能都是你原创的,你为什么要加这个功能?界面布局为什么是这样的?代码为什么要这样写?你必须有自己的理解,并且你的理解要远远高于你的用户,这样才能征服他们,他们才会心甘情愿地付钱给你。

好了,暂时发挥到这,我们会到正题来继续我们的功能。

随着功能的深入,本节补充了DBController的两个函数:

executeReturnLastId用于新建一条记录后,把新建的这条记录的Id值返回。

从零开始用C#做产品:私人日记(15)分类界面与数据库联动

SELECT last_insert_rowid(); 这个sql语句就是返回最新一条的记录值,这个没什么技巧,大家记住就好了。

另外,还上次的提交漏掉了关闭数据库的方法,这次补上来。

从零开始用C#做产品:私人日记(15)分类界面与数据库联动

这样DBController的类算是基本完善了。接下来我们对BAL.Category类进行改进,红框部分为新增加的内容。

从零开始用C#做产品:私人日记(15)分类界面与数据库联动

TableName对应的就是表名。

然后就是执行插入一条记录的SQL语句,得到新记录的Id值,复制给model.Id,返回。

函数过程很简单,下面简单介绍下SQL语句,不同数据库的sql语句大体相似,我们就只说sqlite的:

增、删、改、查的基本格式:

增加:Insert into [表名] ([字段名...多个用,分隔]) values([多个用,分隔])

修改:update [表名] set [字段名]=[值](多个用,分隔) where [条件]

删除:delete from [表名] where [条件]

查询:select * from [表名] where [条件]

上面中括号中的是根据业务不同而变的内容,不带中括号的基本都是标准的写法,照葫芦画瓢就好。基本的sql语法我不详细讲了,大家可以通过教程下方的说明去那个菜鸟看下,这块不难。相对来说查询select语句会更复杂一些,以后用到的地方我会具体讲。

其实数据库操作,说白了就是一堆的符合sql规范的字符串,看你怎么来组合。

直接用sql的方式编程非常灵活,只是在web项目中,由于地址是暴露在公网上,有被注入的风险,这块想要解决也比较容易,等做web项目时我再展开。

BAL.Category类中还有个地方需要解释,就是查询后,需要做一下从hashtable到List的转换:

string sql = string.Format("select * from {0}", TableName);
List results = DBController.Default.query(sql);
List history = new List();
foreach (Hashtable result in results)
{
Model.Category model = new Model.Category();
model.Id = int.Parse(result["Id"].ToString());
model.Name = result["Name"].ToString();
model.ParentId = int.Parse(result["ParentId"].ToString());
model.HasChild = int.Parse(result["HasChild"].ToString()) == 1;
model.Type = result["Type"].ToString();
model.ShowOrder = int.Parse(result["ShowOrder"].ToString());
model.Description = result["Description"].ToString();
model.Remark = result["Remark"].ToString();
history.Add(model);
}
return history;

这块实际上是可以通过抽象类专门写一个类做转换的,不过我们属于入门阶段,暂时不需要过多了解了。以后有需要,我可以再写一个做ORM系列的教程,专门来说这些。

其他改进:

1、新建节点发现一处Bug,创建时CategoryManagerForm应默认选择指定的分类作为父节点;现已修复。

2、CategoryManagerForm的默认输入焦点为备注框,应该按从上到下的顺序。在控件设计界面中调整TabIndex的顺序,0最先,越大越靠后。

3、我们希望MainForm界面启动后显示在屏幕中央。设置窗体的StartPosition属性。

从零开始用C#做产品:私人日记(15)分类界面与数据库联动

4、CategoryManagerForm界面打开后显示在MainForm的中央

从零开始用C#做产品:私人日记(15)分类界面与数据库联动

以上所有代码,均已同步更新到了Gitee上,有需要的同学们自行了解。

本阶段程序的执行演示:

从零开始用C#做产品:私人日记(15)分类界面与数据库联动

至此,我们分类管理界面基本就告一段落了,下一步开始内容管理的设计。

----------------------------------------------------

本教程尽量保证2天一更,项目源码已作为开源项目加入到Gitee,代码内容会随教程实时更新,大家有兴趣的话可以关注我,以获得最及时的更新。私信:

私人日记 可以获取Gitee的链接;sqlitestudio可以获取sqlitestudio的链接;

C#基本语法大家在头条搜索“菜鸟c#”,个人感觉基础知识这个网站还不错。

大家阅读过程中有哪些看不懂或未尽兴的地方,可以在评论区留言,我会先记下来在后续的教程中找机会再说。

教程有帮助的话请大家帮忙关注、转发、扩散,能不能开专栏还需要你们的支持!

展开阅读全文

页面更新:2024-03-24

标签:界面   数据库   全局   静态   语句   实例   私人   声明   模式   操作   代码   功能   程序   项目   教程   日记   内容   产品   科技

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top