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天内更新完,最近自己也在学习

    越是无知的人越是觉得自己无所不知(之前的自己) 越是学习的人越是觉得自己会的太少了(现在的自己) 共勉
  • 相关阅读:
    均匀分布
    吉布斯采样(Gibbs采样)
    蒙特卡罗方法 Monte Carlo method
    马尔科夫链
    python 3 没有了xrange
    %matplotlib inline的含义
    MCMC采样和M-H采样
    pycharm 安装模块 use the correct version of 'pip' installed for your Python interpreter
    Pycharm安装第三方库时出现Read timed out的解决办法
    如何在Pycharm中添加新的模块(第三方包)
  • 原文地址:https://www.cnblogs.com/bwxw/p/15334752.html
Copyright © 2011-2022 走看看