通用属性框架设计

我们设计数据库一般设计方法是横向设计(横向扩展),例如用户表,我们一般设计方法是主表用户表,附表是用户简介表:

这里写图片描述

那么这样设计对吗?我先不回答这个问题。首先主表的信息是我们经常用到的信息,附表的信息是偶尔用到的信息。那么假设,我们有一天需要增加需求通过第三方的平台登录,并且记录用户相关信息,怎么办?唯一的办吧是横向扩展数据库。。Oh MyGod!!!这个动作可不小!

那么有没有方法来避免这个问题呢?回答是肯定的——通用属性框架!什么叫做通用属性框架?就是说,我们把一些容易扩展(将来扩展)的对象放到一个容器中存储,扩展只需要纵向扩展就好了!数据库纵向扩展无非就是增加一条数据而已嘛!如下图的设计:
这里写图片描述

解释下:
Id :主键 int 自增
EntityId :实体主键,int 引用(其他属性实体的主键)
EntityGroupKey :实体类型名称(ToString的字符串就可以)
AttributeName :属性名称
AttributeValue :属性的值

这样表我们就设计好了。
那么如何进行关联呢,看看下图:
这里写图片描述

通用属性表被多张表引用,例如用户、类别等,如果用户有一个属性名为性别,那么通用属性的数据如下:
这里写图片描述
理论数据我们说通了,那么程序如何实现呢?

首先我们增加一个接口IGenericAttributeService

    /// <summary>
    /// 通用用户属性服务接口
    /// </summary>
    public interface IGenericAttributeService: IApplicationService
    {
        /// <summary>
        ///  删除属性
        /// </summary>
        /// <param name="attribute">属性</param>
        void DeleteAttribute(GenericAttribute attribute);

        /// <summary>
        /// 删除属性
        /// </summary>
        /// <param name="attributes">属性</param>
        void DeleteAttributes(IList<GenericAttribute> attributes);

        /// <summary>
        /// 删除属性
        /// </summary>
        /// <param name="attributeId"></param>
        void DeleteAttribute(int attributeId);

        /// <summary>
        /// 删除属性
        /// </summary>
        /// <param name="attributeIds"></param>
        void DeleteAttribute(int[] attributeIds);

        /// <summary>
        /// 获取属性
        /// </summary>
        /// <param name="attributeId">主键</param>
        /// <returns>一个属性</returns>
        GenericAttribute GetAttributeById(int attributeId);

        /// <summary>
        /// 新增属性
        /// </summary>
        /// <param name="attribute">属性</param>
        void InsertAttribute(GenericAttribute attribute);

        /// <summary>
        /// 更新属性
        /// </summary>
        /// <param name="attribute">属性</param>
        void UpdateAttribute(GenericAttribute attribute);

        /// <summary>
        /// 获取属性
        /// </summary>
        /// <param name="entityId">实体主键</param>
        /// <param name="keyGroup">群组</param>
        /// <returns>属性群组</returns>
        IList<GenericAttribute> GetAttributesForEntity(int entityId, string keyGroup);

        /// <summary>
        /// 保存属性
        /// </summary>
        /// <typeparam name="TPropType">属性</typeparam>
        /// <param name="entity">实体</param>
        /// <param name="key">Key</param>
        /// <param name="value">Value</param>
        void SaveAttribute<TPropType>(Entity entity, string key, TPropType value);
    }

这里我解释下,我用的abp框架,所以所有实体都是继承自Entity,建议大家使用CodeFirst开发的时候也有一个基类实体。

这样我们就可以保存实体对应的数据了,那么我要保存一个用户的性别怎么办?首先我把所有的扩展的属性名称,写到了一个静态类里面,在针对这个用户实体写一个扩展类GenericAttributeExtensions

        /// <summary>
        /// 获取实体的属性
        /// </summary>
        /// <typeparam name="TPropType">属性类型</typeparam>
        /// <param name="entity">Entity</param>
        /// <param name="key">Key</param>
        /// <returns>Attribute</returns>
        public static TPropType GetAttribute<TPropType>(this Entity entity, string key)
        {
            var genericAttributeService = IocManager.Instance.Resolve<IGenericAttributeAppService>();
            return GetAttribute<TPropType>(entity, key, genericAttributeService);
        }

        /// <summary>
        /// 获取实体的属性
        /// </summary>
        /// <typeparam name="TPropType">属性类型</typeparam>
        /// <param name="entity">Entity</param>
        /// <param name="key">Key</param>
        /// <param name="genericAttributeService">通用属性服务</param>
        /// <returns>Attribute</returns>
        public static TPropType GetAttribute<TPropType>(this Entity entity,
            string key, IGenericAttributeAppService genericAttributeService)
        {
            if (entity == null)
                throw new ArgumentNullException("entity");

            string keyGroup = entity.GetUnproxiedEntityType().Name;

            var props = genericAttributeService.GetAttributesForEntity(entity.Id, keyGroup);
            if (props == null)
                return default(TPropType);
            props = props.ToList();
            if (!props.Any())
                return default(TPropType);

            var prop = props.FirstOrDefault(ga =>
                ga.Key.Equals(key, StringComparison.InvariantCultureIgnoreCase)); 

            if (prop == null || string.IsNullOrEmpty(prop.Value))
                return default(TPropType);

            return CommonHelper.To<TPropType>(prop.Value);
        }
    }

这样就所有的实体都有了进行读取通用属性的方法了,我没有写存储的方法,建议大家按照例子写一个存储的方法。

欢迎来到qq群进行讨论:68848430

扫一扫更多内容在历史记录

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值