Use AOP to improve Fireasy entity model and aopfireasy entity model

Source: Internet
Author: User

Use AOP to improve Fireasy entity model and aopfireasy entity model

Currently, although the entity model in Fireasy is generated using CodeBuilder, it is still relatively large and difficult to manually maintain. Therefore, I have always wanted to use a simple model, such as only get and set attributes, add a maximum of ColumnAttribute and so on for ing. In this case, the attribute modification feature cannot be maintained, that is, when updating an object, you do not know which attributes have been modified.

Let's take a look at the currently generated entity class code:

/// <Summary> /// Department entity class. /// </Summary> [Serializable] [EntityMapping ("TB_DEPT", Description = "Department")] public partial class Dept: entityObject {# region Static Property Definition /// <summary> /// dependency attribute of the 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> /// encoding dependency attribute. /// </Summary> public static readonly IProperty EpNo = PropertyUnity. registerProperty <Dept> (s => s. no, new PropertyMapInfo {Length = 50, Description = "encoding", FieldName = "NO"}); // <summary> // The name's dependency attribute. /// </Summary> public static readonly IProperty EpName = PropertyUnity. registerProperty <Dept> (s => s. name, new PropertyMapInfo {Length = 50, Description = "NAME", FieldName = "Name"}); // <summary> // sort the dependency attributes. /// </Summary> public static readonly IProperty EpOrderNo = PropertyUnity. registerProperty <Dept> (s => s. orderNo, new PropertyMapInfo {Description = "sort", FieldName = "ORDER_NO"}); # endregion # region Properties // <summary> // obtain or set the ID. /// </Summary> public string Id {get {return (string) GetValue (EpId) ;}set {SetValue (EpId, value );}} /// <summary> /// get or set the encoding. /// </Summary> public string No {get {return (string) GetValue (EpNo);} set {SetValue (EpNo, value );}} /// <summary> /// obtain or set the name. /// </Summary> public string Name {get {return (string) GetValue (EpName);} set {SetValue (EpName, value );}} /// <summary> /// obtain or set the sorting. /// </Summary> public int? OrderNo {get {return (int ?) GetValue (EpOrderNo);} set {SetValue (EpOrderNo, value) ;}# endregion}

The above Entity model mainly draws on the dependency attribute principle in WPF to define a static Field to implement relationship ing. The main point is that when setting attributes, it is executed by the SetValue method of the base class. It records the modified attribute and updates only the modified attribute when updating the object.

GetValue and SetValue seem to have the packing and unpacking operations. In fact, the attribute values are stored in the PropertyValue structure, and data is exchanged through the heavy-load forced conversion and explicit conversion operators, so don't worry.

In fact, it is much easier to implement the EntityObject base class. You can abstract a class and create it based on AOP, after setting the property value and obtaining the property value, call SetValue and GetValue respectively.

Fireasy originally provided AOP. In the Fireasy. Common. Aop namespace, the key is the IInterceptor interface. It binds methods, attributes, or the entire class to be intercepted through the InterceptAttribute feature.

There is also an interface IAopSupport, which only serves as one identifier. In the extension method New, if the type implements IAopSupport, AspectFactory is used to create the object.

Okay. Next we will define a LighEntityObject class:

[Intercept (typeof (LighEntityInterceptor)] public abstract class LighEntityObject <TEntity>: EntityObject, IAopSupport, IEntityPropertyInitialize where TEntity: IEntity {// <summary> // construct a proxy object. /// </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) {// defined as virtual var getMth = property. getGetMethod (); If (getMth! = Null & getMth. IsVirtual &&! GetMth. isFinal) {RegisterProperty (entityType. baseType, property) ;}}} private void RegisterProperty (Type entityType, PropertyInfo property) {// associate attributes, that is, attributes of the correlated object or child body set if (typeof (IEntity ). isAssignableFrom (property. propertyType) | typeof (IEntitySet ). isAssignableFrom (property. propertyType) {var mapping = property. getCustomAttributes <PropertyMappingAttribute> (). firstOrDefault (); var options = mappin G! = 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. getCustomAttr Ibutes <PropertyMappingAttribute> (). FirstOrDefault (); if (mapping! = Null) {InitMapInfo (mapping, gp. info);} PropertyUnity. registerProperty (entityType, gp) ;}/// <summary> /// set the ing information of the property based on the ing property. /// </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 ;}}}

The key is the Interceptor. Check the following code:

    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();                        }                        break;                    case InterceptType.AfterSetValue:                        entity.SetValue(property, info.Arguments[0]);                        break;                }            }        }    }

In fact, it is very easy to call GetValue and SetValue when reading the property value and setting the property value. Is it super simple.

LighEntityObject is defined, but when can I use AOP to generate proxy classes.

Find the VisitConstant method in QueryBinder and add the following section:

        protected override Expression VisitConstant(ConstantExpression c)        {            if (IsQueryable(c))            {                var rowType = c.Type.GetEnumerableElementType();                if (typeof(IEntity).IsAssignableFrom(rowType))                {                    if (typeof(IAopSupport).IsAssignableFrom(rowType))                    {                        rowType = Fireasy.Common.Aop.InterceptBuilder.BuildType(rowType);                    }                    return VisitSequence(QueryUtility.GetTableQuery(EntityMetadataUnity.GetEntityMetadata(rowType)));                }                else                {                    var q = (IQueryable)c.Value;                    return base.Visit(q.Expression);                }            }            return c;        }

 

Now, the transformation is complete, and the entity model is much more refreshing:

/// <Summary> /// Department entity class. /// </Summary> [Serializable] [EntityMapping ("TB_DEPT", Description = "Department")] public partial class Dept: lighEntityObject <Dept >{/// <summary> /// obtain or set the ID. /// </Summary> [PropertyMapping (ColumnName = "ID", Description = "ID", IsPrimaryKey = true, IsNullable = false, Length = 36)] public virtual string Id {get; set ;}/// <summary> /// get or set the encoding. /// </Summary> [PropertyMapping (ColumnName = "NO", Description = "encoding", Length = 50)] public virtual string No {get; set ;} /// <summary> /// obtain or set the name. /// </Summary> [PropertyMapping (ColumnName = "NAME", Description = "Name", Length = 50)] public virtual string NAME {get; set ;} /// <summary> /// obtain or set the sorting. /// </Summary> [PropertyMapping (ColumnName = "ORDER_NO", Description = "sort")] public virtual int? OrderNo {get; set ;}/// <summary >/// obtain or set the <see cref = "Employee"/> fruit body set. /// </Summary> public virtual EntitySet <Employee> Employees {get; set ;}}

Note that attributes must be defined as virtual, otherwise AOP will not recognize them.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.