首页 > 学院 > 开发设计 > 正文

使用AOP改进Fireasy实体模型

2019-11-17 02:27:52
字体:
来源:转载
供稿:网友

使用AOP改进Fireasy实体模型

目前Fireasy中的实体模型虽然用CodeBuilder生成,但是还是比较庞大,手工维护起来比较吃力,因此一直想使用比较简单的一种模型,比如属性只有 get 和 set,最多加个ColumnAttribute之类的来做映射。但这样做的话,属性修改这一特性就无法保持了,即更新实体时不知道哪些属性有改动过。

我们先看一下目前生成的实体类代码:

    /// <summary>    /// 部门 实体类。    /// </summary>    [Serializable]    [EntityMapping("TB_DEPT", Description = "部门")]    public partial class Dept : EntityObject    {        #region Static PRoperty Definition                /// <summary>        /// ID的依赖属性。        /// </summary>        public static readonly IProperty EpId = PropertyUnity.RegisterProperty<Dept>(s => s.Id, new PropertyMapInfo { IsPrimaryKey = true, IsNullable = false, Length = 36, Description = "ID", FieldName = "ID" });        /// <summary>        /// 编码的依赖属性。        /// </summary>        public static readonly IProperty EpNo = PropertyUnity.RegisterProperty<Dept>(s => s.No, new PropertyMapInfo { Length = 50, Description = "编码", FieldName = "NO" });        /// <summary>        /// 名称的依赖属性。        /// </summary>        public static readonly IProperty EpName = PropertyUnity.RegisterProperty<Dept>(s => s.Name, new PropertyMapInfo { Length = 50, Description = "名称", FieldName = "NAME" });        /// <summary>        /// 排序的依赖属性。        /// </summary>        public static readonly IProperty EpOrderNo = PropertyUnity.RegisterProperty<Dept>(s => s.OrderNo, new PropertyMapInfo { Description = "排序", FieldName = "ORDER_NO" });        #endregion        #region Properties                /// <summary>        /// 获取或设置ID。        /// </summary>        public string Id        {            get { return (string)GetValue(EpId); }            set { SetValue(EpId, value); }        }        /// <summary>        /// 获取或设置编码。        /// </summary>        public string No        {            get { return (string)GetValue(EpNo); }            set { SetValue(EpNo, value); }        }        /// <summary>        /// 获取或设置名称。        /// </summary>        public string Name        {            get { return (string)GetValue(EpName); }            set { SetValue(EpName, value); }        }        /// <summary>        /// 获取或设置排序。        /// </summary>        public int? OrderNo        {            get { return (int?)GetValue(EpOrderNo); }            set { SetValue(EpOrderNo, value); }        }        #endregion    }

以上的实体模型,主要借鉴WPF中的依赖属性原理,定义一个静态的Field实现关系映射,最主要的一点,就是在设置属性的时候,交由基类的SetValue方法来执行,它会把这个修改过的属性记下来,在更新实体的时候,达到只更新修改过的属性的目的。

而GetValue和SetValue看似有装箱和拆箱操作,实际上属性的值是以PropertyValue这个结构存储的,通过重载强制转换和显式转换操作符来交换数据,所以这里不用担心啦。

那么,实际上有了EntityObject基类就好办多了,可以再抽象出一个类,让它基于AOP来创建,在设置属性值之后和获取属性值之后分别调用SetValue和GetValue就好了。

Fireasy本来就提供了AOP,在Fireasy.Common.Aop命名空间中,关键是IInterceptor这个接口,它通过InterceptAttribute特性来绑定要拦截的方法、属性或是整个类。

还有一个接口IAopSupport,它只起到一个标识,在扩展方法New中,如果类型实现了IAopSupport,那么则使用aspectFactory来创建对象。

好,接下来我们定义一个LighEntityObject 类:

    [Intercept(typeof(LighEntityInterceptor))]    public abstract class LighEntityObject<TEntity> : EntityObject,         IAopSupport,         IEntityPropertyInitialize        where TEntity : IEntity    {        /// <summary>        /// 构造一个代理对象。        /// </summary>        /// <returns></returns>        public static TEntity New()        {            return typeof(TEntity).New<TEntity>();        }        void IEntityPropertyInitialize.Initialize()        {            var entityType = this.GetType();            foreach (var property in entityType.BaseType.GetProperties(BindingFlags.Public | BindingFlags.Instance))            {                if (property.DeclaringType == entityType.BaseType)                {                    //定义为 virtual                    var getMth = property.GetGetMethod();                    if (getMth != null && getMth.IsVirtual && !getMth.IsFinal)                    {                        RegisterProperty(entityType.BaseType, property);                    }                }            }        }        private void RegisterProperty(Type entityType, PropertyInfo property)        {            //关联属性,即关联实体或子实体集属性            if (typeof(IEntity).IsAssignableFrom(property.PropertyType) ||                typeof(IEntitySet).IsAssignableFrom(property.PropertyType))            {                var mapping = property.GetCustomAttributes<PropertyMappingAttribute>().FirstOrDefault();                var options = mapping != null && mapping.GetFlag(PropertyMappingAttribute.SetMark.LoadBehavior) ?                    new RelationOptions(mapping.LoadBehavior) : null;                PropertyUnity.RegisterSupposedProperty(property.Name, property.PropertyType, entityType, options: options);            }            else            {                var gp = new GeneralProperty()                    {                        Name = property.Name,                        Type = property.PropertyType,                        EntityType = entityType,                        Info = new PropertyMapInfo { ReflectionInfo = property, FieldName = property.Name }                    };                var mapping = property.GetCustomAttributes<PropertyMappingAttribute>().FirstOrDefault();                if (mapping != null)                {                    InitMapInfo(mapping, gp.Info);                }                PropertyUnity.RegisterProperty(entityType, gp);            }        }        /// <summary>        /// 根据映射特性设置属性的映射信息。        /// </summary>        /// <param name="mapping"></param>        /// <param name="mapInfo"></param>        private void InitMapInfo(PropertyMappingAttribute mapping, PropertyMapInfo mapInfo)        {            mapInfo.FieldName = mapping.ColumnName;            mapInfo.Description = mapping.Description;            mapInfo.GenerateType = mapping.GenerateType;            if (mapping.GetFlag(PropertyMappingAttribute.SetMark.DataType))            {                mapInfo.DataType = mapping.DataType;            }            if (mapping.GetFlag(PropertyMappingAttribute.SetMark.IsPrimaryKey))            {                mapInfo.IsPrimaryKey = mapping.IsPrimaryKey;            }            if (mapping.GetFlag(PropertyMappingAttribute.SetMark.IsDeletedKey))            {                mapInfo.IsDeletedKey = mapping.IsDeletedKey;            }            if (mapping.DefaultValue != null)            {                mapInfo.DefaultValue = PropertyValue.New(mapping.DefaultValue, mapInfo.ReflectionInfo.PropertyType);            }            if (mapping.GetFlag(PropertyMappingAttribute.SetMark.Length))            {                mapInfo.Length = mapping.Length;            }            if (mapping.GetFlag(PropertyMappingAttribute.SetMark.Precision))            {                mapInfo.Precision = mapping.Precision;            }            if (mapping.GetFlag(PropertyMappingAttribute.SetMark.Scale))            {                mapInfo.Scale = mapping.Scale;            }        }    }

关键还是拦截器了,看下面代码:

    public sealed class LighEntityInterceptor : IInterceptor    {        void IInterceptor.Initialize(InterceptContext context)        {        }        void IInterceptor.Intercept(InterceptCallInfo info)        {            if (info.InterceptType == InterceptType.AfterGetValue ||                info.InterceptType == InterceptType.AfterSetValue)            {                var entity = info.Target as EntityObject;                var entityType = entity.EntityType;                var property = PropertyUnity.GetProperty(entityType, info.Member.Name);                if (property == null)                {                    return;                }                switch (info.InterceptType)                {                    case InterceptType.AfterGetValue:                        var value = entity.GetValue(property);                        if (value != null && !value.IsEmpty)                        {                            info.ReturnValue = value.GetStorageValue();                        }
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表