zoukankan      html  css  js  c++  java
  • .Net泛型+反射(超实用的文章)包含:泛型缓存,特性,简单工厂

    一.引言

    仅供学习参考使用

    要求:

    1 建立一个数据库,然后执行下面的数据库脚本,会增加两张表 User Company,大家可以去表里面自己多加入一些数据
    
    2 建立数据库表映射的基类BaseModel,包括 Id属性
      建立两个子类Model:公司和用户,按照表结构来
    
    3 提供两个泛型的数据库访问方法,用 BaseModel约束
    一个是用id去查询单个实体,(只有这一个参数)
    一个是查询出数据表的全部数据列表查询(没有参数)
    
    提示:用DataReader去访问数据库,将得到的结果通过反射生成实体对象/集合返回;
    
    4 封装一个方法,能控制台输出任意实体的全部属性和属性值;
    
    5 进阶需求:提供泛型的数据库实体插入、实体更新、ID删除数据的数据库访问方法;
    
    6 进阶需求(可选):欢迎小伙伴儿写个实体自动生成器;
    
    7 进阶需求(可选):将数据访问层抽象,使用简单工厂+配置文件+反射的方式,来提供对数据访问层的使用
    
    8 进阶需求(可选):每个实体类的基础增删改查SQL语句是不变的,用泛型缓存试试!
    
    1 封装一个方法,能控制台输出任意实体的全部属性和属性值  Name:Eleven;
      升级一下,属性名称希望用具体中文描述,而不是实体的属性名,也就是 名称:Eleven;
    
    2 如果数据库的表/字段名称和程序中实体不一致,尝试用特性提供,解决增删改查;
      (数据库是user 程序得是UserModel)
      (数据库是state 程序得是status)
    
    3 通用数据验证,Required(非空)  Mobile(手机号格式) Email(格式) 字符串长度(最大最小)等常见规则;
      支持一个属性多重验证;
      支持返回错误信息;
      支持返回全部错误(一个对象多个属性,可能多个条件都不满足);
    
    4 委托优化,项目中的各种重复代码
    
    5 进阶需求(可选):反射特性的很多东西缓存一下,字典缓存OR泛型缓存
    View Code

     二.代码部分

    1.项目框架如下:

     .Net 5.0控制台项目

     刚开始可能代码断断续续,后期全部完成后会整理

     CommonTool下的类BaseModel

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Training.CommonTool
    {
        public class BaseModel
        {
            public int Id { get; set; }
        }
    }
    BaseModel

    CommonTool下的文件夹AttributeExtend下的类

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Training.CommonTool.AttributeExtend
    {
        public class MattAbstractAttribute:Attribute
        {
            protected string Name;
            public MattAbstractAttribute(string name)
            {
                this.Name = name;
            }
            public string GetName()
            {
                return this.Name;
            }
        }
    }
    MattAbstractAttribute
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Training.CommonTool.AttributeExtend
    {
        [AttributeUsage(AttributeTargets.Class)]
        public class TableAttribute: MattAbstractAttribute
        {
            public TableAttribute(string tableName):base(tableName)
            {
    
            }
        }
    }
    TableAttribute
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Training.CommonTool.AttributeExtend
    {
        [AttributeUsage(AttributeTargets.Property)]
        public class ColumnAttribute: MattAbstractAttribute
        {
    
            public ColumnAttribute(string columnName):base(columnName)
            {
    
            }
        }
    }
    ColumnAttribute
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Training.CommonTool.AttributeExtend
    {
        /// <summary>
        /// 特性帮助类
        /// </summary>
        public static class AttributeHelper
        {
            
            /// <summary>
            /// 获取特性名称(实体name以及字段name)
            /// </summary>
            /// <param name="memberInfo"></param>
            /// <returns></returns>
            //this代表扩展方法
            public static string GetAttributeName(this MemberInfo memberInfo)
            {
                //判断是否存在
                if (memberInfo.IsDefined(typeof(MattAbstractAttribute),true))
                {
                    //GetCustomAttribute获取自定义特性
                    MattAbstractAttribute mattAbstract =memberInfo.GetCustomAttribute<MattAbstractAttribute>();
                    return mattAbstract.GetName();
                }
                //如果未标记特性,就返回原有名称(tablename/Property)
                return memberInfo.Name;
            }
        }
    }
    AttributeHelper

    IService下的IBaseService接口

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Training.CommonTool;
    
    namespace Training.IService
    {
        /// <summary>
        /// 服务层接口
        /// </summary>
        public interface IBaseService
        {
            /// <summary>
            /// 根据id找到某个实体的某一行的数据
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="id"></param>
            /// <returns></returns>
            T Find<T>(int id) where T : BaseModel;
            /// <summary>
            /// 查找到对应实体的全部数据
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <returns></returns>
            List<T> FindAll<T>() where T : BaseModel;
            /// <summary>
            /// 新增接口
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="t"></param>
            /// <returns></returns>
            bool Add<T>(T t) where T : BaseModel;
            /// <summary>
            /// 修改接口
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="t"></param>
            /// <returns></returns>
            bool Update<T>(T t) where T : BaseModel;
            /// <summary>
            /// 删除接口
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="t"></param>
            /// <returns></returns>
            bool Delete<T>(T t) where T : BaseModel;
        }
    }
    IBaseService

    Model层下的类

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Training.Model
    {
        public class Company
        {
            public string Name { get; set; }
    
            public DateTime CreateTime { get; set; }
            public int CreatorId { get; set; }
            public int? LastModifierId { get; set; }
            public DateTime? LastModifyTime { get; set; }
        }
    }
    Company
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Training.CommonTool;
    using Training.CommonTool.AttributeExtend;
    
    namespace Training.Model
    {
        [Table("User")]
        public class UserModel : BaseModel
        {
            public string Name { get; set; }
            [Column("Account")]
            public string AccountName { get; set; }
            public string Password { get; set; }
            public string Email { get; set; }
            public string Mobile { get; set; }
            public int? CompanyId { get; set; }
            public string CompanyName { get; set; }
            public int State { get; set; }
            public int UserType { get; set; }
            public DateTime? LastLoginTime { get; set; }
            public DateTime CreateTime { get; set; }
            public int CreatorId { get; set; }
            public int? LastModifierId { get; set; }
            public DateTime? LastModifyTime { get; set; }
        }
    }
    UserModel

    Service下的BaseService类

    using System;
    using System.Collections.Generic;
    using System.Data.SqlClient;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Training.CommonTool;
    using Training.CommonTool.AttributeExtend;
    using Training.IService;
    
    namespace Training.Service
    {
        public class BaseService : IBaseService
        {
            /// <summary>
            /// 通用的动作:创建、打开、释放连接 sqlcommand创建
            /// </summary>
            /// <param name="sql"></param>
            /// <param name="func"></param>
            /// <returns></returns>
            private T Command<T>(string sql, Func<SqlCommand, T> func)
            {
                using SqlConnection conn = new(ConfigrationManager.SqlConnectionString);
                SqlCommand sqlCommand = new(sql, conn);
                conn.Open();
                //Invoke是调用一个委托,包含一个入参及出参(两个类型参数不同),
                //我们这里调用的是func委托Func<SqlCommand, T>,入参是SqlCommand,出参是T
                return func.Invoke(sqlCommand);
            }
            public bool Add<T>(T t) where T : BaseModel
            {
                Type type = typeof(T);
                //1.首先获取实体的所有字段
                //2.将这些字段拼接成sqlparameter需要的参数
                //3.存在部分字段是空值,所以需要用??判断,如果是空值就返回DBnull.Value,不是空值就返回原本的值
                //4.将添加语句从TSqlHelper类中读取过来
                //5.调用封装好的command方法,将参数及值添加进去
                //6.判断最终的结果成功与否
                var prop = type.GetProperties().Where(s => !s.Name.Equals("Id"));
                var param = prop.Select(s => new SqlParameter($@"{s.GetAttributeName()}", s.GetValue(t) ?? DBNull.Value)).ToArray();
                string sql = $"{TSqlHelper<T>.Addsql}";
                //因为需要写不止一句代码,所以得带方法体{}
                //??表示为空就是DBNull.Value,不为空就返回原来的值
                //因为AddRange方法需要参数SqlParameter[]数组类型的,所以需要调用.ToArray()将返回值转为数组
                //SqlParameter需要传入两个参数,一个是参数名称,另一个是参数值
                //因为我们最终返回true,所以编译器推测返回值是bool,所以就不需要写command返回值类型
                return Command(sql, sqlcommand =>
                {
                    sqlcommand.Parameters.AddRange(param);
                    int result = sqlcommand.ExecuteNonQuery();
                    if (result == 0)
                        throw new Exception("新增异常");
                    return true;
                });
            }
    
            public T Find<T>(int id) where T : BaseModel
            {
                throw new NotImplementedException();
            }
    
            public List<T> FindAll<T>() where T : BaseModel
            {
                throw new NotImplementedException();
            }
    
            public bool Update<T>(T t) where T : BaseModel
            {
                throw new NotImplementedException();
            }
    
            public bool Delete<T>(T t) where T : BaseModel
            {
                throw new NotImplementedException();
            }
        }
    }
    BaseService

    Training下的ConfigrationManager类

    using Microsoft.Extensions.Configuration;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Training
    {
        /// <summary>
        /// 获取配置文件帮助类
        /// </summary>
        public static class ConfigrationManager
        {
            //有了IOC再去注入--容器单例
            static ConfigrationManager()
            {
                var builder = new ConfigurationBuilder()
                        .SetBasePath(Directory.GetCurrentDirectory())
                        .AddJsonFile("appsetting.json");
                IConfigurationRoot configuration = builder.Build();
                _SqlConnectionString = configuration["ConnectionString"];
            }
            private static string _SqlConnectionString = null;
            public static string SqlConnectionString
            {
                get
                {
                    return _SqlConnectionString;
                }
            }
        }
    }
    ConfigrationManager

    Training下的appsetting.json文件

    {
      "ConnectionString": "server=.;uid=sa;pwd=010806wpz.;database=Work;MultipleActiveResultSets=True"
    }
    appsetting.json

    泛型缓存

    Service下的类TSqlHelper(泛型类)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    using System.Threading.Tasks;
    using Training.CommonTool;
    using Training.CommonTool.AttributeExtend;
    
    namespace Training.Service
    {
        /// <summary>
        /// crud语句泛型类
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public  static class TSqlHelper<T> where T:BaseModel
        {
            //泛型约束是为了保证传进来的类型是我们需要的,以免报错类型错误的bug
            //当类与构造函数都为静态时,在调用这个静态类时,会先执行静态构造函数,保存到内存中,在下次调用时直接取,不需要执行,这样就加快了程序的执行效率,提升性能,
            //这个类是泛型静态类时,传入什么类型就会保存什么类型,下次调用其他类型时,会继续执行静态构造函数,无影响
            //因为crud语句需要从这个类里面取,所以需要将他们访问限制设置成公有,方便其他类调用(public)
            public static string Addsql = null;
            public static string Selectsql = null;
            public static string Updatesql = null;
            public static string Deletesql = null;
            //因为tablename以及类型只在内部类中使用,所以不需要公开,访问限制就写为private
            private static Type type = typeof(T);
            //根据泛型传进来的类获取表名
            private static string TableName = type.GetAttributeName();
            //泛型缓存
            static TSqlHelper()
            {
                //string.Join是用来分隔的,第一个以及最后一个字段不会加',',其他都会加','
                //用[]是为了避免表名及字段是关键字
                //一个实体的所有字段
                string columnnName = string.Join(",", type.GetProperties().Where(s=>!s.Name.Equals("Id")).Select(s=>$"[{s.GetAttributeName()}]"));
                //columnValue用@是为了防止sql注入
                //where作用是为了排除id字段,因为id字段数据库设为自增,所以参数和值都将id字段去掉
                //字段值(真正的值会在调用时传入)
                string columnValue = string.Join(",", type.GetProperties().Where(s => !s.Name.Equals("Id")).Select(s=>$"@{s.GetAttributeName()}"));
                string editNameValue = string.Join(",",type.GetProperties()
                    .Where(s=>!s.Name.Equals("Id"))
                    .Select(s=>$"[{s.GetAttributeName()}]=@{s.GetAttributeName()}"));
                Selectsql = $"select [{TableName}] from {columnnName}";
                Addsql = $"insert [{TableName}]({columnnName}) values ({columnValue})";
                Deletesql = $"delete from [{TableName}]";
                Updatesql = $"update [{TableName}] set {editNameValue}";
            }
        }
    }
    TSqlHelper

     会不断更新,具体解释都在代码注释里了,一起进步啊!

    3-5天内更新完,最近自己也在学习

    越是无知的人越是觉得自己无所不知(之前的自己) 越是学习的人越是觉得自己会的太少了(现在的自己) 共勉
  • 相关阅读:
    【LeetCode】048. Rotate Image
    【LeetCode】036. Valid Sudoku
    【LeetCode】060. Permutation Sequence
    【LeetCode】001. Two Sum
    【LeetCode】128. Longest Consecutive Sequence
    【LeetCode】081. Search in Rotated Sorted Array II
    【LeetCode】033. Search in Rotated Sorted Array
    顺时针打印矩阵
    矩形覆盖
    二维数组中的查找
  • 原文地址:https://www.cnblogs.com/bwxw/p/15334752.html
Copyright © 2011-2022 走看看