.NET/C# 高级开发(三) 课程小结

任务需求

一,提供数据库访问方法类,BaseModel约束
二,封装一个方法,在控制台输出任意实体的全部属性和属性值
三,提供泛型数据库实体插入,实体更新,ID删除数据的数据库访问方法
四,写一个实体自动生成器
五,将数据库访问层抽象,使用简单工厂+配置文件+反射的方法,来提供对数据库的访问
六,每个实体类的基础增删改查Sql语句不变,用泛型缓存实现

(一)数据库访问方法类

先把约束写出来,要它有一个自增的键id

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ruanmou.Libraries.Model
{
    public class BaseModel
    {
        public int identification { get; set; }
    }
}

然后根据两个表写两个类
类名属性要与表名属性一一对应

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ruanmou.Libraries.Model
{
    public class Company: BaseModel
    {
        public string password { get; set; }
        public string nickname { get; set; }
        public string gender { get; set; }
        /// <summary>
        /// ?  可控字段
        /// </summary>
        public DateTime? birthday { get; set; }
        public int? property { get; set; }//Nullable<int>


    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ruanmou.Libraries.Model
{
    public class User: BaseModel
    {
        public string password { get; set; }
        public string nickname { get; set; }
        public int? age { get; set; }
        public int? vip { get; set; }
        public DateTime? registration { get; set; }
    }
}

(二)控制台输出任意实体的全部属性和属性值

public static class ConsoleExtend
    {
        //封装一个方法,在控制台输出任意实体的全部属性和属性值
        public static void Show<T>(this T t)
        {
            Type type = t.GetType();
            Console.WriteLine("*******************************************");
            foreach (var prop in type.GetProperties())//获取当前对象全部属性
            {
                Console.WriteLine($"{type.Name}.{prop.Name}={prop.GetValue(t)}");
                
            }
            Console.WriteLine("*******************************************");
        }
    }

(三)泛型数据库实体插入,实体更新,ID删除数据的数据库访问方法

首先是对数据库的约束

using Ruanmou.Libraries.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ruanmou.Libraries.IDAL
{
    public interface IBaseDAL
    {
        T Find<T>(int id) where T : BaseModel;
        List<T> FindAll<T>() where T : BaseModel;
        bool Add<T>(T t) where T : BaseModel;
        bool Updata<T>(T t) where T : BaseModel;
        bool Delete<T>(T t) where T : BaseModel;
    }
}

然后来实现方法

using Ruanmou.Framework;
using Ruanmou.Libraries.IDAL;
using Ruanmou.Libraries.Model;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.SqlClient;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Ruanmou.Libraries.DAL
{
    /// <summary>
    /// 约束调用者,避免其他实体传递进来
    /// BaseModel 保证一定有ID 而且是int 自增主键
    /// </summary>
    public class BaseDAL : IBaseDAL
    {
        public bool Add<T>(T t) where T : BaseModel
        {
            Type type = t.GetType();
            //id是自增的不能新增,要排除id   
            //方法一
            //string columnString = string.Join(",", type.GetProperties()
            //    .Where(p =>!p.Name.Equals("identification"))//如果等于当前属性就去掉,where 返回表达式成立项
            //    .Select(p => $"[{p.Name}]"));//这里的p是Select的参数,取自type.GetProperties()中的每一个成员

            //方法二
            string columnString = string.Join(",", type.GetProperties(BindingFlags.DeclaredOnly|BindingFlags.Instance|BindingFlags.Public)
                .Select(p => $"[{p.Name}]"));//这里的p是Select的参数,取自type.GetProperties()中的每一个成员

            string ValuesColumn = string.Join(",", type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public)
                 .Select(p => $"'@{p.GetValue(t)}'"));//将属性值拼接成字符串返回
            //sqlserver中任意值都可以加引号
            //这里要注意sql注入,Name's 比如这样的,含有注入风险,所以要参数话
            List<SqlParameter> parameterList = type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public)//检索当前类的所有属性,当前级别层的 当前实例的 公共的
                .Select(p => new SqlParameter($"@{p.Name}", p.GetValue(t)??DBNull.Value))//使用检索到的成员实例化成Parameter  参数化p的名字? 判断p的值是否为空,空就传入DBNull
                .ToList();//生成一个新List集合返回

            string sql = $"Insert [{type.Name}] ({columnString}) values({ValuesColumn})";

            using (SqlConnection conn = new SqlConnection(StaticField.ConnectionStringCostomers))
            {
                conn.Open();
                SqlCommand command = new SqlCommand(sql, conn);//创建sql语句
                command.Parameters.AddRange(parameterList.ToArray());//???
                var reader = command.ExecuteReader();//执行sql语句
                return command.ExecuteNonQuery() == 1;
            }

        }

        public bool Delete<T>(T t) where T : BaseModel
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// ID查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id"></param>
        /// <returns></returns>
        public T Find<T>(int id) where T : BaseModel
        {
            Type type = typeof(T);
            //查询语句
            string sql = $"SELECT {string.Join(",", type.GetProperties().Select(p => $"[{p.Name}]"))} FROM [{type.Name}] WHERE identification = {id}";
            object oObject = Activator.CreateInstance(type);
            using (SqlConnection conn = new SqlConnection(StaticField.ConnectionStringCostomers))
            {
                conn.Open();
                SqlCommand command = new SqlCommand(sql, conn);//创建sql语句
                var reader = command.ExecuteReader();//执行sql语句
                if (reader.Read())//将数据指向下一条,默认-1
                {
                    return this.Trans<T>(type,reader);
                }
                else
                {
                    return null;//如果数据库查询不到,应该返回null 而不是默认对象
                }
            }
        }
        /// <summary>
        /// 全部查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public List<T> FindAll<T>() where T : BaseModel
        {
            Type type = typeof(T);
            //查询语句
            //string sql = $"SELECT {string.Join(",", type.GetProperties().Select(p => $"[{p.Name}]"))} FROM [{type.Name}]";
            string sql = SqlBuilder<T>.FindAllSql;
            
            using (SqlConnection conn = new SqlConnection(StaticField.ConnectionStringCostomers))
            {
                conn.Open();
                SqlCommand command = new SqlCommand(sql, conn);//创建sql语句
                var reader = command.ExecuteReader();//执行sql语句
                List<T> tList = new List<T>();
                while (reader.Read())//将数据指向下一条,默认-1
                {
                    tList.Add(this.Trans<T>(type, reader));
                }
                return tList;

            }
        }

        public bool Updata<T>(T t) where T : BaseModel
        {
            throw new NotImplementedException();
        }
        #region Private Method
        private T Trans<T>(Type type, SqlDataReader reader)
        {
            object oObject = Activator.CreateInstance(type);//反射创建泛型参数的实例
            foreach (var prop in type.GetProperties())//获取当前对象全部属性
            {
                //prop.SetValue(oObject, reader[prop.Name]);
                //可空类型,如果数据库存储的是null,返回的是DBnull,DBnull不能直接赋值给可空类型(null),直接SetValue会报错
                //    //处理方法  reader[prop.Name] is DBNull?null: reader[prop.Name]  利用三元运算来确定返回的值是null还是自身的值
                prop.SetValue(oObject, reader[prop.Name] is DBNull ? null : reader[prop.Name]);
            }
            return (T)oObject;
        }
        #endregion

    }
}

删除和更新就不写了,太简单了

(四)写一个实体自动生成器

public static class AutoCreateModel
    {
        //写一个实体自动生成器
        
        private static string GetAllTableSql = "SELECT name FROM sys.tables where type ='U'";
        private static string GetTableInfoSql = @"SELECT DISTINCT 
                                                A.COLUMN_NAME colname,
                                                A.DATA_TYPE typename,
                                                A.IS_NULLABLE isnullable 
                                                From INFORMATION_SCHEMA.Columns A LEFT JOIN 
                                                INFORMATION_SCHEMA.KEY_COLUMN_USAGE B ON 
                                                A.TABLE_NAME=B.TABLE_NAME";


        public static void BatchMappingModel()
        {
            using (SqlConnection conn=new SqlConnection(StaticField.ConnectionStringCostomers))
            {
                SqlCommand sqlCommand = new SqlCommand(GetAllTableSql, conn);
                conn.Open();
                SqlDataReader reader = sqlCommand.ExecuteReader();
                while (reader.Read())
                {
                    MappingModel(reader["name"].ToString());
                }
            }
        }
        public static void MappingModel(string tableName)
        {
            string sql = $"{GetTableInfoSql} where a.table_name='{tableName}'";
            using (SqlConnection conn=new SqlConnection(StaticField.ConnectionStringCostomers))
            {
                SqlCommand sqlcommand = new SqlCommand(sql, conn);
                conn.Open();
                SqlDataReader reader = sqlcommand.ExecuteReader();
                StringBuilder stringBuilder = new StringBuilder();
                stringBuilder.Append($"public class {tableName} \r\n{{\r\n");
                while (reader.Read())
                {
                    stringBuilder.Append($"public {GetTypeOFColumn(reader["typename"].ToString(), reader["isnullable"].ToString())} {reader["colname"]} {{get;set;}}\r\n");
                }
                stringBuilder.Append("}");
                CommonMethod.CreateTxt(StaticField.ModelFilePath + "\\" + tableName + ".txt", stringBuilder.ToString());
            }
        }
        public static string GetTypeOFColumn(string type,string nullAble)
        {
            if (type.Equals("int") && nullAble.Equals("NO"))
                return "int";
            if(type.Equals("int") && nullAble.Equals("YES"))
                return "int?";
            if (type.Equals("datetime") && nullAble.Equals("NO"))
                return "datetime";
            if (type.Equals("datetime") && nullAble.Equals("YES"))
                return "datetime?";
            if (type.Equals("nvarchar") || type.Equals("varchar") || type.Equals("text"))
                return "string";
            else throw new Exception($"暂不支持_类型:{type}_可空:{nullAble}_");
        }
    }
    public static class CommonMethod
    {
        public static void CreateTxt(string a,string b)
        {
            //根据路径和文本内容生成文本
            FileStream fs = new FileStream(a,FileMode.Create);
            StreamWriter sw = new StreamWriter(fs);
            sw.Write(b);
            sw.Flush();
            sw.Close();
            fs.Close();
        }
    }

(五)使用简单工厂+配置文件+反射的方法,来提供对数据库的访问

配置文件类

public static class StaticField
    {
        //配置文件常量类
        /// <summary>
        /// 数据库读写类配置文件
        /// </summary>
        public readonly static string IBaseDALConfig = ConfigurationManager.AppSettings["IBaseDALConfig"];
        /// <summary>
        /// 实体生成器路径配置文件
        /// </summary>
        public readonly static string ModelFilePath = ConfigurationManager.AppSettings["ModelFilePath"];
        /// <summary>
        /// 数据库连接账号配置文件
        /// </summary>
        public readonly static string ConnectionStringCostomers = ConfigurationManager.ConnectionStrings["ConnectionStringCostomers"].ConnectionString;
        /// <summary>
        /// 数据表接口配置文件
        /// </summary>
        public static class BaseModelConfig
        {
            private readonly static string BaseModelConfigString= ConfigurationManager.AppSettings["BaseModelConfig"];
            /// <summary>
            /// 完整DLL名称
            /// </summary>
            public readonly static string DllName ;
            /// <summary>
            /// 类名称
            /// </summary>
            public readonly static string ClassName ;
            static BaseModelConfig()
            {
            DllName = BaseModelConfigString.Split(',')[0];//用逗号分隔一下,分隔后的数组第一个就是dll名了
            ClassName = BaseModelConfigString.Split(',')[1];//第二个就是类名了
            }
        }
    }

简单工厂+反射

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Ruanmou.Libraries.Factory
{
    public static class ReflectClass<T> where T : class
    {
        private static T _class;
        private static Type _type;
        public static T foundClass (string dllName, string className, params object[] obj)
        {
            if (_class != null) return _class;
            return found(dllName, className, obj);
        }
        public static T foundNewClass (string dllName, string className, params object[] obj)
        {
            if (_type != null) return Activator.CreateInstance(_type, obj) as T;
            return found(dllName, className, obj);
        }
        
        #region found
        private static T found(string dllName, string className, params object[] obj)
        {
            className = dllName + "." + className;
            Type[] type = typeof(T).GenericTypeArguments;
            Assembly assembly0 = Assembly.Load(dllName);
            _type = assembly0.GetType(className);
            if (typeof(T).IsGenericType)
                _type = _type.MakeGenericType(type);
            object oDBHelper = Activator.CreateInstance(_type, obj);
            _class = oDBHelper as T;
            return _class;
        }
        #endregion

    }
    public static class ReflectMethod
    {
        public static object InvokeMethod(this object function, string method, params object[] obj)
        {
            List<Type> listType = new List<Type>();
            Type[] type = new Type[] { };
            foreach (var o in obj)
            {
                listType.Add(o.GetType());
            }
            type = listType.ToArray();
            MethodInfo method_0 = function.GetType().GetMethod(method, type);
            MethodInfo newMethod = method_0.MakeGenericMethod(new Type[] { typeof(int), typeof(string), typeof(DateTime) });
            return method_0.Invoke(function, obj);
        }

    }
}

(六)泛型缓存实现实体类的增删改查Sql

using Ruanmou.Libraries.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Ruanmou.Libraries.DAL
{
    public class SqlBuilder<T>where T:BaseModel
    {
        public static string FindSql = null;
        public static string FindAllSql = null;
        public static string AddSql = null;
        public static string DeleteSql = null;
        public static string UpDataSql = null;
        static SqlBuilder()
        {
            FindSql = $"SELECT {string.Join(",", typeof(T).GetProperties().Select(p => $"[{p.Name}]"))} FROM [{typeof(T).Name}] WHERE identification = @id";

            FindAllSql = $"SELECT {string.Join(",", typeof(T).GetProperties().Select(p => $"[{p.Name}]"))} FROM [{typeof(T).Name}]";
#region
            string columnString = string.Join(",", typeof(T).GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public)
                .Select(p => $"[{p.Name}]"));//这里的p是Select的参数,取自type.GetProperties()中的每一个成员
            string ValuesColumn = string.Join(",", typeof(T).GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public)
                 .Select(p => $"'@{p.Name}'"));//将属性值拼接成字符串返回
#endregion
            AddSql = $"Insert [{typeof(T).Name}] ({columnString}) values({ValuesColumn})";

            DeleteSql = $"";

            UpDataSql = $"";
        }
    }
}

(七)整体结构图

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值