C#实现一个简单的SQLite ORM框架记录

有个项目需要保存多个配置项,配置项可能随着开发不断增加。偏向使用SQLite数据库配合ORM(对象关系映射)来实现。

因为要求并不复杂,就打算自己简单实现一下,练下手。

这里记录遇到的一些点。

  1. C#中的泛型类,可以看作时针对某种泛型生成了新的类。比如类声明的静态代码块(静态构造函数static ClassName(){}会在使用新的泛型时重新执行。不同泛型,类的静态变量也不互通。
  2. 类的readonly字段只能在声明期间或构造函数赋值(包括静态构造函数,当然这种情况需要变量也是静态的)。

反射

  1. 反射可通过System.Type对象实现,Type对象可由typeof(ClassName)obj.getType()获得。
  2. 类内容的获取:Type对象有一系列Get()方法,可以访问类内的属性(即有get()set()的变量)、变量、方法等,返回值都是封装好的对象或是对象集合。
  3. 实例的创建,Activator.CreateInstance()
    T t=Activator.CreateInstance<T>();
    
  4. 泛型实例属性读写(SetValue()/GetValue()):
    public void Increase(T t)
    {
        var propA = typeof(T).GetProperty("A");
        var value = propA.GetValue(t, null);
        if (propA.PropertyType == typeof(int))
        {
            var result = int.Parse(value.ToString()) + 1;
            propA.SetValue(t, result, null);
        }
    }
    

特性(注解)

  1. 通过继承System.Attribute类即可。
    public class NonSQL : Attribute
    {
    
    }
    
    class Person
    {
        [NonSQL]
        public string FirstName {get;set;}
    }
    
  2. 想要获取属性的特性,可以通过PropertyInfo.GetCustomAttributes()即可获取,其他如字段等也有类似方法。

SQLite

  1. SQLite对alter的支持有限,字段一旦添加,就不能通过alter语句修改字段的属性(类型、主键等)。
  2. 查找表是否存在,(0-表名):
    select count(*)  from sqlite_master where type='table' and name = '{0}';
    
  3. 建表,(0-表名;1-以逗号隔开的字段定义):
    create table if not exists {0} ({1});
    
  4. 添加字段,(0-表名;1-字段定义):
    alter table {0} add column {1};
    
  5. 插入,(0-表名;1-以逗号隔开的字段;2-以逗号隔开的字段对应值):
    insert or replace into {0} ({1}) values ({2});
    
  6. where子句使用:以and连接多个条件,除了逻辑运算符外,还可以使用like做字符匹配,百分号(%)代表零个、一个或多个数字或字符,下划线(_)代表一个单一的数字或字符,符号可被组合使用。
  7. 执行查询时会返回SQLiteDataReader对象,有很多方法,这里说两个常用的。
    1. 通过Read()读取一列数据,读取成功返回true。
    2. 通过["{PropName}"]可以直接读取字段的值。
  8. 两种执行语句的方法
    // 只是执行一条SQL语句
    private void ExecuteNonQuery(string sql)
    {
        lock (connection)
        {
            EnsureDatabaseConnected();
            using (var tr = connection.BeginTransaction())
            {
                using (var command = connection.CreateCommand())
                {
                    command.CommandText = sql;
                    command.ExecuteNonQuery();
                }
                tr.Commit();
            }
        }
    }
    
    // 执行一条SQL语句,并执行提供的操作,一般用于查询
    private void ExecuteQuery(string sql, Action<SQLiteDataReader> action)
    {
        lock (connection)
        {
            EnsureDatabaseConnected();
            using (var command = connection.CreateCommand())
            {
                command.CommandText = sql;
                var reader = command.ExecuteReader();
                action(reader);
            }
        }
    }
    
    //后一种的使用示例
    public int GetTableCount(string tableName)
    {
        var tableCount = 0;
        var tableCountSql = string.Format("select count(*)  from sqlite_master where type='table' and name = '{0}';", tableName);
    
        ExecuteQuery(tableCountSql, reader =>
        {
            reader.Read();
            tableCount = reader.GetInt32(0);
        });
    
        return tableCount;
    }
    

其他

  1. 尽量使用泛型方法而不是泛型类。
  2. String.IsNullOrWhiteSpace(),除了null和空字符串(String.IsNullOrEmpty()判断范围),还扩展了空白字符的判断。
  3. C#中有一个System.IO.Path类,可以很方便的拼接文件路径、提取文件所在文件夹等。并且操作是跨平台的。
    原文作者:KwokKwok
    原文地址: https://www.jianshu.com/p/dcca189fed01
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞