爱摄叽歪

爱生活爱叽歪,一个不务正业的人!

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

在项目中,经常会需要对一些特定的业务对象进行属性的扩展,而且这些属性的扩展还具备极不可预测性、相互关系松散等特点。大部分的开发人员是最讨厌这类涉及到数据字段扩展的需求变更。这种调整,轻则数据要加字段,重则程序代码要做大量的调整。在几微助手的开发过程中,也会涉及大量的类似需求的变更、扩展,甚至随着业务发展,自然就有大量的新的东东需要进行扩展。
1、以产品例,随着业务发展,产品的管理的字段不断增加,比如:是否支持配送、是否可以用优惠券......
2、以订单为例,每个已经支付的订单,状态要细化3-4重状态(例:发货、待发货等),订单要记录优惠券、订单的来源等
3、以用户为例,那需要扩展的用户资料项更是不了,经常就要多几个
....
既然这么复杂,那就需要找点方法来偷懒,偷懒的目标:
1、遇到类似的琐碎的属性扩展不需要在修改数据库字段、增加字段/属性后不需要大范围的代码调整
2、基于C#面向对象的思路,每一给扩展属性,可以回归到主体对象
3、未来属性的扩展允许多种方式:A、直接扩展主体代码内的属性;B、允许继承后扩展;
4、支持属性的无限扩展,底层的数据库可拆可和,可以根据业务需求改变储存
5、未来的扩展开发只需要关注属性扩展可以业务逻辑,无需重复底层的数据开发

基于以上目标,我们初步在整理一下开发/设计思路:
1、以Key-Value方式来做数据库扩展,理论上从数据库的角度看可以纵向无线扩展
2、为了与数据的自动匹配对应记录,可以自己定义一个字典对象,用一个字典对象与数据库对接进行存储
3、字典对象的Key为扩展的属性名,支持预定义代码级扩展配置文件扩展,理论上支持这三种方式,后期的代码维护就简单了
4、将数据存储放在基类提供统一的操作方法,预留数据库文件的操作扩展性

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

这里很简单,数据库里面就两张表(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)其实用系统默认提供的一些字典对象也可以干,不过我比较喜欢强类型,这里就全自己定义个类型,在代码里面看到这个东东就知道这个玩意是我自己的一个扩展属性。

   /// <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);
        }

    }

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

    /// <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 { get; set; }

    }

 

不允许评论