在项目中,经常会需要对一些特定的业务对象进行属性的扩展,而且这些属性的扩展还具备极不可预测性、相互关系松散等特点。大部分的开发人员是最讨厌这类涉及到数据字段扩展的需求变更。这种调整,轻则数据要加字段,重则程序代码要做大量的调整。在几微助手的开发过程中,也会涉及大量的类似需求的变更、扩展,甚至随着业务发展,自然就有大量的新的东东需要进行扩展。不需要在修改数据库字段、增加字段/属性后不需要大范围的代码调整合,可以根据业务需求改变储存5、未来的扩展开发只需要关注属性扩展可以业务逻辑,无需重复底层的数据开发

基于以上目标,我们初步在整理一下开发/设计思路:预定义代码级扩展配置文件扩展,理论上支持这三种方式,后期的代码维护就简单了

好了下面开始!先做好数据库设计:

这里很简单,数据库里面就两张表(SettingExtensions:通用扩展表,ModuleItemSettiingExtensions:单项个别扩展表),这里我们线建立一个概念,将所有扩展看做是原主体对象的设置。另外,有些主体对象可能还是一个集合,例如产品,那么这里我们可以把全部产品的管理当成一个主模块,对于这个主模块,可能会有需要扩展的通用的属性,那么在这个模块内的每个产品项(这里我们展示叫ModuleItem)还会有自己的单独扩展项,可能是从通用继承,可能是特殊的。

所以数据库就这两张表,一张放通用、一张放个别,如果需要开发的对象无所谓通用、个别的关系,那么我就统一放在SettingExtensions。关于字段,就比较简单了,主要是Key,Value字段,value是一个长文本字段,便于未来可以存放json、转成base64的二进制等复杂对象。另外在SettingExtensions里面多了一个TypeName,这个主要是区别一下模块类型名称,众多模块如果放在一个数据库,Key是有可能重复的。在ModuleItemSettiingExtensions表里面,ModuleType是记录当前个别项所属的集合类型名,同SettingExtensions->TypeName,ModuleItemID就是当前Item主体在系统中的唯一ID,例如:这个项是扩展产品的属性,那这里就应该是产品ID

开始写代码,先自定义以个Key-Value的对象,这里我们从DictionaryBase继承,在此基础上扩展,主要是忽略掉Key的大小写(我不喜欢大小写敏感的Key)其实用系统默认提供的一些字典对象也可以干,不过我比较喜欢强类型,这里就全自己定义个类型,在代码里面看到这个东东就知道这个玩意是我自己的一个扩展属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/// <summary>
 /// 自定义设置的字典对象,继承DictionaryBase,
 /// 在SettingDictionary实现中索引或者设置键值对,对键key的大小写不敏感
 /// </summary>
 public class SettingDictionary:DictionaryBase
 {
     public event ItemChanged OnItemChanged;
     /// <summary>
     /// 添加键值对到hashtable
     /// </summary>
     /// <param name="key"></param>
     /// <param name="value"></param>
     public virtual void Add(string key, string value)
     {
         this.InnerHashtable.Add(key.ToLower(), value);
     }
     /// <summary>
     /// 获取或设置键值对中的值
     /// </summary>
     /// <param name="key"></param>
     /// <returns></returns>
     public string this[string key]
     {
         get
         {
             return (string)this.InnerHashtable[key.ToLower()];
         }
         set
         {
             if (this.ContainsKey(key) || !this.InnerHashtable[key.ToLower()].Equals(value))
             {
                 if (this.OnItemChanged != null)
                     this.OnItemChanged(this, key);
             }
             this.InnerHashtable[key.ToLower()] = value;
         }
     }
     /// <summary>
     /// 判断关键字是否存在
     /// </summary>
     /// <param name="key"></param>
     /// <returns></returns>
     public bool ContainsKey(string key)
     {
         return this.InnerHashtable.ContainsKey(key.ToLower());
     }
     private class SettingDictionaryEnumerator : IDictionaryEnumerator
     {
         DictionaryEntry[] items;
         Int32 index = -1;
         public SettingDictionaryEnumerator(SettingDictionary settings)
         {
             items = new DictionaryEntry[settings.Count];
             settings.CopyTo(items, 0);
             //items.OrderBy(m => m.Key);
             //Array.Reverse(items);
         }
         // 返回当前项
         public Object Current { get { ValidateIndex(); return new SettingItem { Key = items[index].Key.ToString(), Value = items[index].Value.ToString() }; } }
         // 返回当前字典实例
         public DictionaryEntry Entry
         {
             get return (DictionaryEntry)Current; }
         }
         // 返回当前项的Key
         public Object Key { get { ValidateIndex(); return items[index].Key; } }
         // 返回当前项目的Value
         public Object Value { get { ValidateIndex(); return items[index].Value; } }
         public Boolean MoveNext()
         {
             if (index < items.Length - 1) { index++; return true; }
             return false;
         }
         private void ValidateIndex()
         {
             if (index < 0 || index >= items.Length)
                 throw new InvalidOperationException("超出项目索引边界");
         }
         public void Reset()
         {
             index = -1;
         }
     }
     public IDictionaryEnumerator GetEnumerator()
     {
         return new SettingDictionaryEnumerator(this);
     }
 }

为字典对象的单项定义一个强类型结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/// <summary>
/// 设置项目的结构
/// </summary>
public struct SettingItem
{
    private string _key;
    /// <summary>
    /// 设置实例的键(名称)
    /// </summary>
    public string Key { get return this._key.ToLower(); } set this._key = value.ToLower(); } }
    /// <summary>
    /// 设置实例的值
    /// </summary>
    public string Value { getset; }
}

基于SQLite+EF6实现一套自己的Key-Value存储管理工具包(1)相关推荐

  1. 基于SQLite+EF6实现一套自己的Key-Value存储管理工具包(2)

    上一篇里面整理了一下需求和思路,自定义了扩展的字典对象,这里我们再继续深入编码. BaseExtensions类,这个类作未来任何需要Key-Value形式扩展的基类 1 2 3 4 5 6 7 8 ...

  2. 基于SQLite+EF6实现一套自己的Key-Value存储管理工具包(3)

    前面两边的代码就是一套初步的工具包架构,基本底层通用,可以移植到任意项目实现类似的需求.接下来,再在我们特定的项目几微助手里面再实现一套基于自己项目的基类,根据项目需求抽象一下项目内的常用方法.理论上 ...

  3. 基于UDP协议的socket套接字编程 基于socketserver实现并发的socket编程

    基于UDP协议 的socket套接字编程 1.UDP套接字简单示例 1.1服务端 import socketserver = socket.socket(socket.AF_INET,socket.S ...

  4. sqlite c++插入 timestamp_Dqlite,基于sqlite 高可用(HA)数据库

    原文发表于我的博客, 特此版权声明 noosphere.site: Dqlite,基于sqlite 高可用(HA)数据库 csdn : Dqlite,基于sqlite 高可用(HA)数据库 k3s之前 ...

  5. mysql sqlite 分页查询_php基于SQLite实现的分页功能示例

    本文实例讲述了php基于SQLite实现的分页功能.分享给大家供大家参考,具体如下: 这里操作数据库文件使用的是前面文章<PHP基于PDO实现的SQLite操作类[包含增删改查及事务等操作]&g ...

  6. 基于嗅探原理的原始套接字木马

    首先我们说说现有木马的特点和功能.早期木马一般都是基于TCP连接的,现在这种木马的生存能力 非常有限,因为直接基于连接的木马很容易被拦截或者发现.然后有通过改变协议来实现通讯隐藏的木马, 比如采用UD ...

  7. C# 错误 175: 具有固定名称“System.Data.SQLite.EF6”的 ADO.NET 提供程序未在计算机或应用程序配置文件中注册或无法加载

    进入C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config找到machine.config 在configuration -> system ...

  8. 人效提高350%,基于KICP搭建的营销套电客服机器人,让欧派家居赢在起点

    当前,90后甚至部分00后成为了家居消费的主力军.生活节奏一再加快,使人们获取信息的习惯发生了转变,更多的消费者不再直奔家居建材城咨询选购,而是选择在购买家居产品之前,通过线上渠道先行了解. 消费者的 ...

  9. 2021年基于VUE开发的一套移动端APP小说 听书AI男女多种 支持云端存储书籍记录

    2021年基于VUE开发的一套移动端APP小说 前端架构主要采用: "axios": "^0.21.1", "better-scroll": ...

最新文章

  1. 基于CASIA-GaitDatasetB步态图像轮廓数据库的步态周期检测与步态角度特征MATLAB源码
  2. C#强化系列文章五:动态代码的使用(反射和动态生成类)
  3. oracle index contention,Index Contention等待
  4. POJ - 2411 Mondriaan's Dream(状压dp)
  5. IT公司100题-14-排序数组中和为给定值的两个数字
  6. bzoj 3714: [PA2014]Kuglarz
  7. abb机器人指令手册_「ABB」ABB机器人指令模块介绍与开发过程
  8. easyui常用控件样式收藏
  9. 社会计算经典谈——书籍销量预测
  10. 区块链社会:解码区块链全球应用与投资案例
  11. 良心!苹果启动 MacBook Pro 电池更换计划
  12. qt 元对象 和moc原理
  13. [效率提升]webstorm配置Prettier
  14. 数字图像处理实验(七)| 形态学图像处理{生成结构元素strel、腐蚀运算imerode、膨胀运算imdilate、开运算imopen、闭运算imclose}(附代码和实验截图、汉字视力表项目、总结)
  15. 涪陵创新计算机学校2015元旦晚会,喜报:重庆市涪陵信息技术学校2019高考再续辉煌...
  16. Centos系统内核优化参数列表
  17. 二进制与其他进制的转换
  18. 如何治理VOCs有机废气的方法——吸附
  19. wordcloud出错_我在安装wordcloud时出错
  20. PVE世界常见的存储格式,qcow2/raw/vmdk

热门文章

  1. 使用目录服务和 Visual C# .NET 向本地系统添加用户
  2. java 多线程 优先级_java多线程之线程的优先级
  3. instancing render
  4. 如何关闭Struts2的webconsole.html
  5. 使用Vue构建中(大)型应用
  6. android 蓝牙各种UUID(转载)
  7. Hibernate简单例子以及笔记
  8. ylbtech-Model-Account(通用账户模块设计)
  9. 使用Windbg内核调试连接调试用户态程序的方法
  10. WPF中的触发器(Trigger)