.Net/C#性能与语法优化-1

相信大家在用EF对数据库数据进行操作的时候,会感觉有一些实体之间的来回转换非常的繁琐,一个表如果有几十个字段,有时候要逐个复制,显得代码累赘,繁琐,操作性能也不是很好,特别是遇到二次更改时候,更是难受,一个字段一个字段找,改。!!下面我就说几个关于语法优化的写法。

一、我先新建两个类,等下所有操作都是基于这两个类进行

这两个类只是一个示例,数据库中新建的表做的示范!!!,示范!!!

1、第一个是数据库中一个表的全部实体

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Models
{
    //数据库实体类
    [Table("Users")]
    public class Users
    {
        /// <summary>
        /// id
        /// </summary>
        [Key]
        public Guid Uid { get; set; } = Guid.Empty;
        /// <summary>
        /// 名称
        /// </summary>
        public string UName { get; set; } = string.Empty;
        /// <summary>
        /// 密码
        /// </summary>
        public string Pwd { get; set; } = string.Empty;
    }
}

2、第二个是我等下用来转换的,将数据库实体批量转换为网站实体,可隐藏敏感数据,属性名称和类型需一一对应

namespace RedisCeShi.Model
{
    //我想让他们看到的,或者说是,我想让他们操作的数据
    public class ReqUsers
    {
        public string UName { get; set; }
        public string Pwd { get; set; }
    }
}

二、代码中常见的写法(优化前!!!没有优化的时候)

我这里就直接给大家复制全部了,大家都能看得懂,不在一 一举例了

/// <summary>
/// 测试查询全部
/// </summary>
/// <returns></returns>
[HttpGet]
public async Task<ActionResult> GetUsers()
{
    var list = await _db.Users.ToListAsync();
    return Ok(list);
}



/// <summary>
/// 添加测试
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
[HttpPost]
public async Task<ActionResult> InsertList(ReqUsers user)
{

    try
    {
       Users model = new Users();
        model.Uid = 0;
        model.UName = user.UName;
        model.Pwd = user.Pwd;
        await _db.Users.AddAsync(model);
        int num = await _db.SaveChangesAsync();
        if (num > 0)
        {
            return Ok("添加成功");
        }
        return BadRequest("添加失败");
    }
    catch (Exception ex)
    {

        return BadRequest($"添加失败:{ex.Message}");
    }
}


/// <summary>
/// 测试编辑
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
[HttpPost]
public async Task<ActionResult> UpdataModel(Users user)
{

    var model = await _db.Users.AsNoTracking().FirstOrDefaultAsync(m => m.Uid == user.Uid);
    if (model is not null)
    {
        model.UName = user.UName;
        model.Pwd = user.Pwd;
        var entry = _db.Entry(model);//跟踪实体的属性更改以及将更改保存回数据库
        entry.State = EntityState.Modified;// 应将其状态标记为已修改   
        if (await _db.SaveChangesAsync() > 0)
        {
            return Ok("编辑成功");
        }
    }

    return BadRequest("编辑失败");
}

在语法没有优化的时候,我这个表只有三个字段,查起来还是代码简洁,比较轻便的,但是如果字段多的时候,我们就会写很多实体字段附加,很没有效率。所以我们就要另找方法。⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇

 三、创建辅助类(优化方法封装)

1、生成表达式目录树  泛型缓存(实现批量实体转换)

using System.Linq.Expressions;
using System.Reflection;

namespace RedisCeShi.Common
{
    /// <summary>
    /// 生成表达式目录树  泛型缓存
    /// </summary>
    /// <typeparam name="TIn"></typeparam>
    /// <typeparam name="TOut"></typeparam>
    public class ExpressionGenericMapper<TIn, TOut>//Mapper`2
    {
        private static Func<TIn, TOut> _FUNC = null;
        private static Func<TIn, TOut, TOut> _FUNC2 = null;
        public static TOut Trans(TIn t)
        {
            return _FUNC(t);
        }

        /// <summary>
        /// 批量实体转换
        /// </summary>
        /// <param name="list">被转换的实体List</param>
        /// <returns></returns>
        public static List<TOut> TransList(List<TIn> list)
        {
            List<TOut> outs = new List<TOut>();
            foreach (var item in list)
            {
                outs.Add(Trans(item));
            }
            return outs;
        }

        /// <summary>
        /// 把TOut 按照TIn来更新
        /// </summary>
        /// <param name="news"></param>
        /// <param name="old"></param>
        /// <returns></returns>
        public static TOut Modify(TIn news, TOut old)
        {
            return _FUNC2(news, old);
        }

        static ExpressionGenericMapper()
        {
            Type stringType = typeof(string);
            #region 创建构造对象的委托
            {
                ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "m");
                List<MemberBinding> memberBindingList = new List<MemberBinding>();
                foreach (var item in typeof(TOut).GetProperties())
                {
                    var type = typeof(TIn);
                    if (item.PropertyType.IsClass && item.PropertyType != stringType)//排除String以外的引用类型,不进行赋值
                    {
                        continue;
                    }
                    var prop = type.GetProperty(item.GetMappingName());//从Out类找映射的字段名
                    if (prop != null)//如果TIn里能找到该属性
                    {

                        MemberExpression property = Expression.Property(parameterExpression, prop);
                        MemberBinding memberBinding = Expression.Bind(item, property);
                        memberBindingList.Add(memberBinding);
                    }
                }
                foreach (var item in typeof(TOut).GetFields())
                {
                    var type = typeof(TIn);
                    if (item.FieldType.IsClass && item.FieldType != stringType)//排除String以外的引用类型,不进行赋值
                    {
                        continue;
                    }
                    var prop = type.GetField(item.GetMappingName());//从Out类找映射的字段名
                    if (prop != null)
                    {
                        MemberExpression property = Expression.Field(parameterExpression, prop);
                        MemberBinding memberBinding = Expression.Bind(item, property);
                        memberBindingList.Add(memberBinding);
                    }

                }
                MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
                Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[]
                {
                    parameterExpression
                });
                _FUNC = lambda.Compile();//拼装是一次性的
            }
            #endregion
            #region 修改对象的委托
            {




                ParameterExpression oExpression = Expression.Parameter(typeof(TOut), "o");
                ParameterExpression nExpression = Expression.Parameter(typeof(TIn), "n");
                List<MemberBinding> memberBindingList = new List<MemberBinding>();
                foreach (var item in typeof(TOut).GetProperties())
                {
                    var type = typeof(TIn);
                    if (item.PropertyType.IsClass && item.PropertyType != stringType)//排除String以外的引用类型,不进行赋值
                    {
                        continue;
                    }
                    var prop = type.GetProperty(item.GetMappingName());
                    if (prop != null)
                    {
                        MemberExpression property = Expression.Property(nExpression, prop);
                        MemberBinding memberBinding = Expression.Bind(item, property);
                        memberBindingList.Add(memberBinding);
                    }
                    else
                    {
                        var propOld = typeof(TOut).GetProperty(item.Name);
                        MemberExpression property = Expression.Property(oExpression, propOld);
                        MemberBinding memberBinding = Expression.Bind(item, property);
                        memberBindingList.Add(memberBinding);
                    }
                }
                foreach (var item in typeof(TOut).GetFields())
                {
                    var type = typeof(TIn);
                    if (item.FieldType.IsClass && item.FieldType != stringType)//排除String以外的引用类型,不进行赋值
                    {
                        continue;
                    }
                    var prop = type.GetField(item.GetMappingName());
                    if (prop != null)
                    {
                        MemberExpression property = Expression.Field(nExpression, prop);
                        MemberBinding memberBinding = Expression.Bind(item, property);
                        memberBindingList.Add(memberBinding);
                    }
                    else
                    {
                        var propOld = typeof(TOut).GetField(item.Name);
                        MemberExpression property = Expression.Field(oExpression, propOld);
                        MemberBinding memberBinding = Expression.Bind(item, property);
                        memberBindingList.Add(memberBinding);
                    }
                }
                MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
                Expression<Func<TIn, TOut, TOut>> lambda = Expression.Lambda<Func<TIn, TOut, TOut>>(memberInitExpression, new ParameterExpression[]
                {
                   nExpression, oExpression
                });
                _FUNC2 = lambda.Compile();//拼装是一次性的
            }
            #endregion
        }




    }


    public static class ExpressionGenericMapperExtend
    {
        public static string GetMappingName(this PropertyInfo prop)
        {

            if (prop.IsDefined(typeof(MappingAttribute), true))
            {
                MappingAttribute display = prop.GetCustomAttribute(typeof(MappingAttribute)) as MappingAttribute;
                return display.MappingName;
            }
            return prop.Name;

        }

        public static string GetMappingName(this FieldInfo prop)
        {

            if (prop.IsDefined(typeof(MappingAttribute), true))
            {
                MappingAttribute display = prop.GetCustomAttribute(typeof(MappingAttribute)) as MappingAttribute;
                return display.MappingName;
            }
            return prop.Name;

        }
    }




    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
    public class MappingAttribute : Attribute
    {
        public string MappingName;
        public MappingAttribute(string _MappingName)
        {
            this.MappingName = _MappingName;
        }


    }
}

2、对象值比较(修改时比较是否修改过字段)

namespace RedisCeShi.Common
{
    /// <summary>
    /// 对象值比较
    /// </summary>
    public static class ObjectEqualsExtend
    {
        /// <summary>
        /// 对比两个对象属性值扩展方法,只针对一个对象下的“属性值”
        /// 仅支持常规数据类型比较,对象下的属性是:(如String int Guid Double DateTime decimal bool 类型)
        /// </summary>
        /// <typeparam name="ObjectA">比较对象A泛型类型</typeparam>
        /// <typeparam name="ObjectB">比较对象B泛型类型</typeparam>
        /// <param name="objectA">对象A</param>
        /// <param name="objectB">对象B</param>
        /// <returns></returns>
        public static bool IsEqualsValue<ObjectA, ObjectB>(this ObjectA objectA, ObjectB objectB)
            where ObjectB : class
            where ObjectA : class
        {
            var propA = objectA.GetType().GetProperties();
            var typeB = objectB.GetType();
            bool flag = true;
            foreach (var item in propA)
            {
                var propB = typeB.GetProperty(item.Name);//从B里找到属性
                if (propB != null)
                {
                    if (item.PropertyType.Name == "Decimal" && (decimal)item.GetValue(objectA) != (decimal)propB.GetValue(objectB))
                    {
                        flag = false;//该返回比较结果不相等了
                        break;//退出循环
                    }
                    else if (item.PropertyType.Name != "Decimal" && item.GetValue(objectA).ToString() != propB.GetValue(objectB).ToString())//如果属性值不相等
                    {
                        flag = false;//该返回比较结果不相等了
                        break;//退出循环
                    }
                }
            }
            return flag;
        }
    }
}

四、优化后代码

代码里所运用的实体均是我上面写的两个示例实体Users,ReqUsers,方便大家查看!!!!

1、查询

/// <summary>
/// 测试
/// </summary>
/// <param name="pageIndex"></param>
/// <param name="pageSize"></param>
/// <param name="Name"></param>
/// <returns></returns>
[HttpGet]
public async Task<ActionResult> GetList(int pageIndex = 1, int pageSize = 10)
{
    //验证数据,返回错误提示
    if (pageIndex < 1 || pageSize < 1)
    {
        return BadRequest("参数有误");
    }
    var list = await _db.Users.Where(m => m.Uid != null).OrderByDescending(m => m.Uid).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync();
    var recordCount = await _db.Users.Where(m => m.Uid != null).CountAsync();
    //Users里面又Id但是我不想让别人看见,我的ReqUsers里面没有Id这个字段,所以用这个转换一下就可以隐藏敏感字段
    var result = ExpressionGenericMapper<Users, ReqUsers>.TransList(list);
    return Ok(result);
}

2、添加

/// 添加测试
/// <summary>
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
[HttpPost]
public async Task<ActionResult> InsertList(ReqUsers user)
{

    try
    {
        //添加时候,我们也可以隐藏敏感字段在后台自己设置,这里我只让他填写ReqUsers里面的字段,然后通过下述方法转换成Users实体,自己在后端定义敏感字段
        var model = ExpressionGenericMapper<ReqUsers, Users>.Trans(user);
        model.Uid = Guid.NewGuid();
        await _db.Users.AddAsync(model);
        int num = await _db.SaveChangesAsync();
        if (num > 0)
        {
            return Ok("添加成功");
        }
        return Ok("添加失败");
    }
    catch (Exception ex)
    {

        return Forbid($"添加失败:{ex.Message}");
    }
}

3、编辑修改

/// <summary>
/// 测试编辑
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
[HttpPost]
public async Task<ActionResult> UpdataModel(Users user)
{
    try
    {
        //AsNoTracking() 是 EF Core 中的一个方法,用于查询实体时指示 EF Core 不要跟踪实体的更改。使用 AsNoTracking() 方法可以提高查询性能,并减少内存消耗。
        var model = await _db.Users.AsNoTracking().FirstOrDefaultAsync(m => m.Uid == user.Uid);
        //验证实体是否有修改,有修改执行if没修改直接返回成功
        if (!user.IsEqualsValue(model))
        {
            //表达式目录是进行实体转换
            var modify = ExpressionGenericMapper<Users, Users>.Modify(user, model);
            //使用 EntityEntry 对象来获取或设置实体的状态、属性值和原始值,以及跟踪实体属性的更改。
            var entry = _db.Entry(modify);
            //将 modify 实体附加到上下文中的 Users 实体集合
            _db.Set<Users>().Attach(modify);
            //其状态标记为已修改。
            entry.State = EntityState.Modified;
            int num = await _db.SaveChangesAsync();
            if (num > 0)
            {
                return Ok("编辑成功");
            }
        }
        else
        {
            return Ok("编辑成功");
        }
        return BadRequest("编辑失败");
    }
    catch (Exception e)
    {

        return BadRequest("内部错误" + e.Message);
    }
}

以上就是进行数据库操作时的方法,每个语句中我都标有注释,拿走直接就能用,小白都能看得懂!

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值