自己实现的一个简单的EF框架(反射实现)
Posted 小曲isme
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自己实现的一个简单的EF框架(反射实现)相关的知识,希望对你有一定的参考价值。
我实现了一个简单的EF框架,主要用于操纵数据库。实现了对数据库的基本操纵--CRUD
这是项目结构 这是一个 core 下的 DLL
写了一个数据库工厂,用于执行sql语句。调用sql语句工厂
写了一个sql语句工厂,用于生成sql语句。调用类型工厂
写了一个类型工厂,用于获取所需的类型,识别特性等。
appsettings.json是配置文件
最后一个是使用说明
我实现过程的首先从底层开始。
首先写的是类型工厂
结构
BaseTypeHelper.cs 是基础的类型帮助类
TypeHelperFactory.cs是一个工厂,调用BaseTypeHelper.cs,是现自己的功能,同时为sql语句工厂提供服务。
首先介绍一下BaseTypeHelper.cs类。这是代码。为TypeHelperFactory提供了必要的服务
1 public static class BaseTypeHelper 2 { 3 #region 获取单个成员 4 private static MemberInfo GetOneMember(Type t, string MemberName) 5 { 6 return GetAllMembers(t).FirstOrDefault(m => m.Name == MemberName); 7 } 8 9 #endregion 10 11 #region 获取所有成员 12 public static MemberInfo[] GetAllMembers(Type t) 13 { 14 return t.GetMembers(); 15 } 16 17 #endregion 18 19 #region 获取成员的属性 20 21 /// <summary> 22 /// 获取成员的属性 23 /// </summary> 24 /// <param name="obj">目标类</param> 25 /// <param name="MemberName">成员名称</param> 26 /// <returns></returns> 27 private static PropertyInfo GetProperty(object obj, string MemberName) 28 { 29 var type = obj.GetType(); 30 var member = GetOneMember(type, MemberName); 31 return type.GetProperty(member.Name); 32 33 } 34 #endregion 35 36 #region 执行法并返回结果 37 /// <summary> 38 /// 获取方法的返回值 39 /// </summary> 40 /// <param name="MethodName">方法的名称</param> 41 /// <param name="instance">实例</param> 42 /// <param name="param">参数列表,如果没有参数则置为null</param> 43 /// <returns></returns> 44 public static object GetMethodValue(string MethodName, object instance, params object[] param) 45 { 46 Type t = instance.GetType(); 47 try 48 { 49 MethodInfo info = t.GetMethod(MethodName); 50 return info.Invoke(instance, param); 51 } 52 catch (Exception e) 53 { 54 Console.WriteLine("方法没有找到," + e); 55 throw; 56 } 57 58 } 59 #endregion 60 61 #region 获取声明成员的类型 62 63 /// <summary> 64 /// 获取声明成员的类型 65 /// 说明:返回若为空则 没有找到 66 /// 若不为空,则查找正常 67 /// </summary> 68 /// <param name="MemberName">成员的名称</param> 69 /// <param name="t">所在类的类型</param> 70 /// <returns></returns> 71 public static string GetPropertyType(string MemberName, Type t) 72 { 73 MemberInfo member = GetOneMember(t, MemberName); 74 if (member != null) 75 { 76 PropertyInfo property = t.GetProperty(member.Name); 77 return property.PropertyType.Name; 78 } 79 return null; 80 81 } 82 #endregion 83 84 #region 获取单个成员是否含有某个属性 85 86 87 /// <summary> 88 /// 获取单个成员是否含有某个特性 89 /// </summary> 90 /// <param name="MemberName">成员的名称</param> 91 /// <param name="t">所在类的类型</param> 92 /// <param name="attribute">要获取的特性</param> 93 /// <returns></returns> 94 public static bool CustomAttributeExist(string MemberName, Type t, Attribute attribute) 95 { 96 97 var Member = GetOneMember(t, MemberName); 98 var My_customAttribute = Member.CustomAttributes.FirstOrDefault( 99 a => a.AttributeType == attribute.GetType()); 100 return My_customAttribute != null; 101 } 102 #endregion 103 104 #region 通过SetValue给成员设值 105 106 /// <summary> 107 /// 给成员设值 108 /// </summary> 109 /// <param name="obj">目标类</param> 110 /// <param name="MemberName">类内属性名称</param> 111 /// <param name="value">设置的值</param> 112 public static void SetValue(object obj, string MemberName, object value) 113 { 114 var Property = GetProperty(obj, MemberName); 115 Property.SetValue(obj, value); 116 } 117 #endregion 118 119 #region 通过GetValue给成员取值 120 121 /// <summary> 122 /// 取成员的值 123 /// </summary> 124 /// <param name="obj">目标类</param> 125 /// <param name="MemberName">成员的名称</param> 126 /// <returns></returns> 127 public static object GetValue(object obj, string MemberName) 128 { 129 var Property = GetProperty(obj, MemberName); 130 return Property.GetValue(obj); 131 } 132 #endregion 133 134 135 }
这是TypeHelperFactory.cs 这是一个工厂,利用BaseTypeHelper.cs 提供的服务的基础之上为上层,提供这么几个功能,获取所有的属性列表,获取属性和值的字典集,获取主键(实现了特性[key]的识别,以及默认的ID.toLower()),获取表名(这里获取表名的时候,只是简单的实现了获取类的名称,并没有实现获取特性[Table(Name="...")]这个功能,会在以后更新上去的),获取主键的名称,获取主键的值,获取声明主键的类型,给属性设值。
1 public static class TypeHelperFactory 2 { 3 #region GetAllPropertyList 4 5 public static List<string> GetAllPropertyList(Type type) 6 { 7 var Propertys = BaseTypeHelper 8 .GetAllMembers(type) 9 .ToList() 10 .FindAll(member => member.MemberType == MemberTypes.Property); 11 var PropertyList = new List<string>(); 12 foreach (var item in Propertys) 13 { 14 PropertyList.Add(item.Name); 15 } 16 return PropertyList; 17 } 18 19 #endregion 20 21 #region GetAllPropertyNameAndValueDictionary 22 //添加到字典中的时候已经去除掉空的值 23 public static Dictionary<string, object> GetAllPropertyNameAndValueDictionary(object obj) 24 { 25 Type type = obj.GetType(); 26 var PropertyList = GetAllPropertyList(type); 27 var PropertyValueList = new Dictionary<string, object>(); 28 foreach (var Property in PropertyList) 29 { 30 var value = BaseTypeHelper.GetValue(obj, Property); 31 if (value == null) continue; 32 PropertyValueList.Add(Property, value); 33 } 34 return PropertyValueList; 35 } 36 37 #endregion 38 39 #region GetTableName 40 /// <summary> 41 ///简单获取类的名称 42 /// 未查找特性[table(Name="")]的标注 43 /// 2017-5-9 18:00 44 /// Author :曲 45 /// </summary> 46 /// <param name="type"></param> 47 /// <returns></returns> 48 public static string GetTableName(Type type) 49 { 50 return type.Name; 51 } 52 53 #endregion 54 55 #region GetPrimaryKey 56 57 public static string GetPrimaryKey(Type type) 58 { 59 //1.查找特性标注为key的 60 //2.如果不存在 查找 类型为int和名称为ID/Id/id 的 61 var memberNameList = GetAllPropertyList(type); 62 var attrribute = new KeyAttribute(); 63 64 foreach (var item in memberNameList) 65 { 66 if (BaseTypeHelper.CustomAttributeExist(item, type, attrribute)) 67 { 68 return item; 69 } 70 } 71 return memberNameList.FirstOrDefault( 72 key => key.ToLower() == "id" 73 && BaseTypeHelper 74 .GetPropertyType(key, type) 75 .Contains("Int") 76 ); 77 78 } 79 80 #endregion 81 82 #region GetPrimaryKeyValue 83 84 public static object GetPrimaryKeyValue(object obj, string PrimaryKeyName) 85 { 86 return BaseTypeHelper.GetValue(obj, PrimaryKeyName); 87 } 88 89 #endregion 90 91 #region GetPrimaryKeyType 92 93 public static string GetPrimaryKeyType(Type type, string PrimaryKey) 94 { 95 return BaseTypeHelper.GetPropertyType(PrimaryKey, type); 96 } 97 98 99 #endregion 100 101 #region SetPropertyValue 102 103 public static void SetPropertyValue(object obj, string MemberName, object value) 104 { 105 BaseTypeHelper.SetValue(obj, MemberName, value); 106 } 107 108 #endregion 109 }
接下来写的是sql语句构造工厂,这是工厂结构。
两个文件夹,一个实现接口文件夹,一个接口文件夹。两个类,一个枚举类,一个对外提供服务的类,也就是外界只能通过这一个类,获取我这一层对外提供的服务。
首先介绍一下接口文件夹 :里边定义了接口的类型,以及方法
里边有五个接口,分别是ICreate、IDelete、IRead、IUpdate、ISqlStatementBuilder。
对这五个接口进行说明一下,ISqlStatementBuilder是总的接口,即对外提供服务的接口,分别继承了CURD这四个接口。
public interface ISqlStatementBuilder : ICreate, IRead, IUpdate, IDelete { }
1 public interface ICreate 2 { 3 string CreateSqlString(object obj); 4 }
1 public interface IDelete 2 { 3 string DeleteSqlString(object obj); 4 5 }
1 public interface IRead 2 { 3 string ReadSqlString(object obj); 4 }
1 public interface IUpdate 2 { 3 string UpdateSqlString(object obj); 4 }
接下来是:实现接口文件夹,这个文件夹包含了三类数据库的对应的sql不同的sql语句。mysql,Oracle,SqlServer,这里我只实现了sqlserver对应的数据库的sql语句。
public class SqlServerSqlStatement :ISqlStatementBuilder { #region 获取Insertsql语句 实现ICreate接口 public string CreateSqlString(object obj) { var type = obj.GetType(); var TableName = TypeHelperFactory.GetTableName(type); var PrimaryKeyName = TypeHelperFactory.GetPrimaryKey(type); var PropertyNameAndValueDictionary = TypeHelperFactory.GetAllPropertyNameAndValueDictionary(obj); PropertyNameAndValueDictionary.Remove(PrimaryKeyName); //这里进行了修改 2017-5-17 17:10 //这是原来的代码 //var PropertyNameList = new List<string>(); //var PropertyValueList = new List<object>(); //foreach (var item in PropertyNameAndValueDictionary) //{ // PropertyNameList.Add(item.Key); // PropertyValueList.Add(item.Value); //} //这是新的代码 测试已通过 以后考虑用元组实现 2017-5-17 17:15 var PropertyNameList = from item in PropertyNameAndValueDictionary select item.Key; var PropertyValueList = from item in PropertyNameAndValueDictionary select item.Value; string sql1 = string.Join(",", PropertyNameList); string sql2 = "\'"; sql2 += string.Join("\',\'", PropertyValueList); sql2 += "\'"; var SqlStatement = new StringBuilder(); SqlStatement.AppendFormat($"insert into {TableName} ({sql1}) values ({sql2})"); return SqlStatement.ToString(); } #endregion #region 获取Readsql语句 实现IRead接口 public string ReadSqlString(object obj) { var type = obj.GetType(); var PropertyList = TypeHelperFactory.GetAllPropertyList(type); var TableName = TypeHelperFactory.GetTableName(type); string SelectString = string.Join(",", PropertyList); StringBuilder SqlStatement = new StringBuilder(); SqlStatement.AppendFormat($"select {SelectString} from {TableName}"); return SqlStatement.ToString(); } #endregion #region 获取Updatesql语句 实现IUpdate接口 public string UpdateSqlString(object obj) { var type = obj.GetType(); var TableName = TypeHelperFactory.GetTableName(type); var PrimaryKeyName = TypeHelperFactory.GetPrimaryKey(type); if (PrimaryKeyName == null) { throw new Exception("不存在主键"); } var PrimaryKeyValue = TypeHelperFactory.GetPrimaryKeyValue(obj, PrimaryKeyName); var PropertyNameAndValueDictionary = TypeHelperFactory.GetAllPropertyNameAndValueDictionary(obj); PropertyNameAndValueDictionary.Remove(PrimaryKeyName); //这里进行了修改 2017-5-17 17:00 //这是原来的代码 //var NameAndValueList = new List<string>(); //foreach (var item in PropertyNameAndValueDictionary) //{ // NameAndValueList.Add($"{item.Key}=\'{item.Value}\'"); //} //这是新的代码 2017-5-17 17:00 测试已通过 var NameAndValueList = from item in PropertyNameAndValueDictionary select $"{item.Key}=\'{item.Value}\'"; string sql = string.Join(",", NameAndValueList); StringBuilder sqlStatement = new StringBuilder(); sqlStatement.AppendFormat( $"update {TableName} set {sql} " + $"where {PrimaryKeyName}=\'{PrimaryKeyValue}\'" ); return sqlStatement.ToString(); } #endregion #region 获取Deletesql语句 实现IDelete接口 public string DeleteSqlString(object obj) { var type = obj.GetType(); var TableName = TypeHelperFactory.GetTableName(type); var PrimaryKey = TypeHelperFactory.GetPrimaryKey(type); if (PrimaryKey == null) { throw new Exception("不存在主键"); } var PrimaryKeyValue = TypeHelperFactory.GetPrimaryKeyValue(obj, PrimaryKey); StringBuilder SqlStatement = new StringBuilder(); SqlStatement.AppendFormat($"delete from {TableName} where {PrimaryKey}=\'{PrimaryKeyValue}\'"); return SqlStatement.ToString(); } #endregion }
这个类实现了ISqlStatementBuilder这个接口里边定义的方法。其余的两个类只是继承了接口,并没有实现接口定义的具体方法。
接下来这一层的重点来了!
首先这是一个数据库的枚举类