我实现了一个简单的EF框架,主要用于操纵数据库。实现了对数据库的基本操纵--CRUD
这是项目结构 这是一个 core 下的 DLL
写了一个数据库工厂,用于执行sql语句。调用sql语句工厂
写了一个sql语句工厂,用于生成sql语句。调用类型工厂
写了一个类型工厂,用于获取所需的类型,识别特性等。
appsettings.json是配置文件
最后一个是使用说明
我实现过程的首先从底层开始。
首先写的是类型工厂
结构
BaseTypeHelper.cs 是基础的类型帮助类
TypeHelperFactory.cs是一个工厂,调用BaseTypeHelper.cs,是现自己的功能,同时为sql语句工厂提供服务。
首先介绍一下BaseTypeHelper.cs类。这是代码。为TypeHelperFactory提供了必要的服务
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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="...")]这个功能,会在以后更新上去的),获取主键的名称,获取主键的值,获取声明主键的类型,给属性设值。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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这四个接口。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
public interface ISqlStatementBuilder : ICreate, IRead, IUpdate, IDelete { }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 public interface ICreate 2 { 3 string CreateSqlString(object obj); 4 }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 public interface IDelete 2 { 3 string DeleteSqlString(object obj); 4 5 }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 public interface IRead 2 { 3 string ReadSqlString(object obj); 4 }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 public interface IUpdate 2 { 3 string UpdateSqlString(object obj); 4 }
接下来是:实现接口文件夹,这个文件夹包含了三类数据库的对应的sql不同的sql语句。MySql,Oracle,SqlServer,这里我只实现了sqlserver对应的数据库的sql语句。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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这个接口里边定义的方法。其余的两个类只是继承了接口,并没有实现接口定义的具体方法。
接下来这一层的重点来了!
首先这是一个数据库的枚举类
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
/// <summary> /// 这是一个枚举类型 用于枚举数据库的类型 /// </summary> public enum DataBaseType { SqlServer = 1, MySql = 2, Oracle = 3 }
接下来这是对外提供服务的一个类,我用反射获取枚举过来的数据库的类型字符串,然后通过反射生成对应的实例。(这个东西的详细用法,我的这篇博客里有介绍http://www.cnblogs.com/qulianqing/p/6842829.html)
1 public static class SqlBuilderFactory 2 { 3 public static ISqlStatementBuilder GetInstance(DataBaseType DbType) 4 { 5 string DataBaseTypeName = Enum.Parse(DbType.GetType(), DbType.ToString()).ToString(); 6 var NamespaceName = "MyEntityFrameWork.SqlBuilderFactorys.Implement"; 7 string InstanceClassName = DataBaseTypeName + "SqlStatement"; 8 return (ISqlStatementBuilder)Assembly.Load(new AssemblyName("MyEntityFrameWork")) 9 .CreateInstance(NamespaceName+"."+InstanceClassName); 10 } 11 12 }
对于外界调用只用这样声明里边参数只用传递对应的数据库的类型。
ISqlStatementBulider SqlBuilder = SqlBuilderFactory.GetInstance(DataBaseType.SqlServer);
这样做的好处是:对于拓展我是支持的,对于外界调用者,他并不知道我是怎么实现的,我用什么方式实现的,以及怎么使用。他只需改变传递的枚举参数就可以了。
如果说以后加入了Access类型的数据库,我只用在枚举类中加入Access的枚举,在实现文件夹中添加AccessSqlStatement.cs这样的一个类,让它实现ISqlSatementBulider接口定义的方法,这样就完成了。这样做我个人感觉拓展很容易。具体是什么设计模式,我也忘了,反正就是这个思想。
接下来我们进入了第三层,也就是目前来说的最高层,也是算是应用层。
这一层是 一个数据库工厂,用于执行sql语句。调用sql语句的工厂
这是这一层的结构,首先是一个基类文件夹,一个实现文件夹,一个接口文件夹(目前为空尚未使用)
在基类文件夹中声明了一个抽象类BasicsDatabase.cs这是一个基类,定义了需要实现的方法。(我仿照着.net core 下的asp.net mvc 项目里的StartUp.cs的构造函数,实现了一个我自己用的一个构造函数。读取json配置文件必须用的一个IConfigurationRoot )
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 public abstract class BasicsDatabase 2 { 3 protected ISqlStatementBuilder SqlBuilder { get; set; } 4 protected IDbConnection Connection { get; set; } 5 public IConfigurationRoot Configuration { get; } 6 protected IDbCommand Command { get; set; } 7 protected BasicsDatabase() 8 { 9 var builder = new ConfigurationBuilder() 10 .SetBasePath(Directory.GetCurrentDirectory()) 11 .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); 12 Configuration = builder.Build(); 13 } 14 15 protected abstract string DatabaseConncetionString(); 16 public abstract List<T> GetAllInfo<T>() where T : new(); 17 public abstract bool Add(object data); 18 public abstract bool Update(object data); 19 public abstract bool Remove(object data); 20 }
接下来是实现文件夹
分别实现了三种不同的数据库,我这里只是实现了SqlServer的数据库类型。其他两个只是演示了怎么使用,以及怎么实现。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 public class SqlServerDatabase : BasicsDatabase 2 { 3 public SqlServerDatabase() : base() 4 { 5 base.Connection = new SqlConnection(DatabaseConncetionString()); 6 Connection.Open(); 7 base.Command = new SqlCommand(); 8 Command.Connection = base.Connection; 9 //这里重要 10 base.SqlBuilder = SqlBuilderFactory.GetInstance(DataBaseType.SqlServer); 11 } 12 13 public override List<T> GetAllInfo<T>() 14 { 15 Command.CommandText = SqlBuilder.ReadSqlString(new T()); 16 var Result = Command.ExecuteReader(CommandBehavior.SingleResult); 17 var AllInfoList = new List<T>(); 18 while (Result.Read()) 19 { 20 var Record = (IDataRecord)Result; 21 AddOneObjectToList(ref AllInfoList, Record); 22 } 23 24 Result.Dispose(); 25 return AllInfoList; 26 } 27 28 private void AddOneObjectToList<T>(ref List<T> objectList, IDataRecord record) where T : new() 29 { 30 //获取所有的特性名称 31 //查找record中的字段名称是否相同 32 //如果相同将其值赋给该字段 33 var PropertyNames = TypeHelperFactory.GetAllPropertyList(typeof(T)); 34 var Obj = new T(); 35 for (int i = 0; i < record.FieldCount; i++) 36 { 37 var PropertyName = PropertyNames.FirstOrDefault(name => name == record.GetName(i)); 38 if (PropertyName != null) 39 { 40 TypeHelperFactory.SetPropertyValue(Obj, PropertyName, record[i]); 41 } 42 43 } 44 objectList.Add(Obj); 45 } 46 public override bool Add(object data) 47 { 48 Command.CommandText = SqlBuilder.CreateSqlString(data); 49 return Command.ExecuteNonQuery() > 0; 50 } 51 public override bool Remove(object data) 52 { 53 Command.CommandText = SqlBuilder.DeleteSqlString(data); 54 return Command.ExecuteNonQuery() > 0; 55 } 56 57 public override bool Update(object data) 58 { 59 Command.CommandText = SqlBuilder.UpdateSqlString(data); 60 return Command.ExecuteNonQuery() > 0; 61 } 62 63 protected override string DatabaseConncetionString() 64 { 65 return base.Configuration.GetConnectionString("DataContext"); 66 } 67 68 }
重点代码已经在注释中标注。这里给大家提一个醒在 24行的代码出,如果用.close()这个方法的话,add,和Update方法都没有问题,但是在Delete方法执行的时候会抛IDataReader没有关闭,请关闭后再使用的异常,用.dispose()这个方法可以解决。这是微软官网给的IDataReader样例https://docs.microsoft.com/en-us/dotnet/api/system.data.idatareader?view=netcore-1.1他用的是Close()这个方法,我刚开始也是用的是close(),这个方法,后来找了好久,改为dispose()就好了,具体原因还没有深入了解。
这是其余两个只是演示了怎么使用
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 public class MySqlDataBase : BasicsDatabase 2 { 3 /// <summary> 4 /// 这是MySql数据库的实现方式 5 /// 只用于演示并没有实现功能 6 /// 时间:2017-5-12 7 /// Author:曲 8 /// </summary> 9 public MySqlDataBase() : base() 10 { 11 base.Connection = new MySqlConnection(); 12 base.Connection.Open(); 13 base.Command = new MySqlCommand(); 14 base.Command.Connection = base.Connection; 15 base.SqlBuilder = SqlBuilderFactory.GetInstance(DataBaseType.MySql); 16 } 17 public override bool Add(object data) 18 { 19 base.Command.CommandText = SqlBuilder.CreateSqlString(data); 20 return base.Command.ExecuteNonQuery() > 0; 21 } 22 23 public override List<T> GetAllInfo<T>() 24 { 25 throw new NotImplementedException(); 26 } 27 28 public override bool Remove(object data) 29 { 30 throw new NotImplementedException(); 31 } 32 33 public override bool Update(object data) 34 { 35 throw new NotImplementedException(); 36 } 37 38 protected override string DatabaseConncetionString() 39 { 40 throw new NotImplementedException(); 41 } 42 }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 /// <summary> 2 /// Oracle数据库的实现方式 3 /// 这是只是用于演示并没有真正实现 4 /// 时间:2017-5-12 5 /// Author:曲 6 /// </summary> 7 public class OracleDataBase : BasicsDatabase 8 { 9 10 public OracleDataBase() : base() 11 { 12 //base.Connection = new OracleConnection(DatabaseConncetionString()); 13 //Connection.Open(); 14 //base.Command = new OracleCommmand(); 15 //Command.Connection = Connection; 16 //base.SqlBuilder = SqlBuilderFactory.GetInstance(DataBaseType.Oracle); 17 } 18 public override bool Add(object data) 19 { 20 Command.CommandText = SqlBuilder.CreateSqlString(data); 21 return Command.ExecuteNonQuery() > 0; 22 } 23 24 public override List<T> GetAllInfo<T>() 25 { 26 throw new NotImplementedException(); 27 } 28 29 public override bool Remove(object data) 30 { 31 throw new NotImplementedException(); 32 } 33 34 public override bool Update(object data) 35 { 36 throw new NotImplementedException(); 37 } 38 39 protected override string DatabaseConncetionString() 40 { 41 throw new NotImplementedException(); 42 } 43 }
这里还是挺丑的毕竟每个子类都要知道具体的实现步骤,准备把子类构造函数里的构造过程,放到抽象类中去,不知道能不能行的通,待明天尝试
到了这里我的EF框架大致就模拟成功了,可以实现CRUD到数据库中。
关于使用,我写了一个 使用说明.md文件。上边有配置步骤,可以一步步的配置然后就可以使用了。
配置我自己定义的服务(这里实现的是sqlServer类型的数据库,如果实现了其他类型的,在这里改动一下就行了)
1 //添加我自己的服务,这里声明的类型为基类型性,实现的是sqlServer的的数据库的类型。 2 services.AddScoped<BasicsDatabase, SqlServerDatabase>();
我在core环境下建了一个mvc项目
在views文件夹中添加一个UserInfo文件夹
里边有这么几个文件和用EF框架生成的一样,不过这里要进行手工的写,
在Controller文件夹中添加一个mvc控制器 在控制器中是是这么用的
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 using Microsoft.AspNetCore.Mvc; 2 using MyEntityFrameWork.DateBaseFactory.BaseClass; 3 using System; 4 using System.Linq; 5 using TestMyEntityFramework.Models; 6 7 // For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 8 9 namespace TestMyEntityFramework.Controllers 10 { 11 public class UserInfoController : Controller 12 { 13 private readonly BasicsDatabase _context; 14 public UserInfoController(BasicsDatabase Database) 15 { 16 _context = Database; 17 } 18 19 // GET: /<controller>/ 20 public IActionResult Index() 21 { 22 23 return View(_context.GetAllInfo<Users>()); 24 } 25 public IActionResult Create() 26 { 27 return View(); 28 } 29 [HttpPost] 30 [ValidateAntiForgeryToken] 31 public IActionResult Create([Bind("ID,Name,pwd")] Users userInfo) 32 { 33 if (ModelState.IsValid) 34 { 35 _context.Add(userInfo); 36 return RedirectToAction("Index"); 37 } 38 return View(userInfo); 39 } 40 public IActionResult Edit(int? id) 41 { 42 if (id == null) 43 { 44 return NotFound(); 45 } 46 47 var userInfo = _context.GetAllInfo<Users>().FirstOrDefault(u=>u.ID==id); 48 if (userInfo == null) 49 { 50 return NotFound(); 51 } 52 return View(userInfo); 53 } 54 55 [HttpPost] 56 [ValidateAntiForgeryToken] 57 public IActionResult Edit(int id, [Bind("ID,Name,pwd")] Users userInfo) 58 { 59 if (id != userInfo.ID) 60 { 61 return NotFound(); 62 } 63 64 if (ModelState.IsValid) 65 { 66 try 67 { 68 _context.Update(userInfo); 69 70 } 71 catch 72 { 73 if (!UserInfoExists(userInfo.ID)) 74 { 75 return NotFound(); 76 } 77 else 78 { 79 throw new Exception("数据更新失败"); 80 } 81 } 82 return RedirectToAction("Index"); 83 } 84 return View(userInfo); 85 } 86 87 public IActionResult Delete(int? id) 88 { 89 if (id == null) 90 { 91 return NotFound(); 92 } 93 94 var userInfo = _context.GetAllInfo<Users>() 95 .SingleOrDefault(m => m.ID == id); 96 if (userInfo == null) 97 { 98 return NotFound(); 99 } 100 101 return View(userInfo); 102 } 103 104 [HttpPost, ActionName("Delete")] 105 [ValidateAntiForgeryToken] 106 public IActionResult DeleteConfirmed(int id) 107 { 108 var userInfo = _context.GetAllInfo<Users>().SingleOrDefault(m => m.ID == id); 109 110 _context.Remove(userInfo); 111 return RedirectToAction("Index"); 112 } 113 114 public IActionResult Details(int? id) 115 { 116 if (id == null) 117 { 118 return NotFound(); 119 } 120 121 var userInfo = _context.GetAllInfo<Users>() 122 .SingleOrDefault(m => m.ID == id); 123 if (userInfo == null) 124 { 125 return NotFound(); 126 } 127 128 return View(userInfo); 129 } 130 private bool UserInfoExists(int id) 131 { 132 return _context.GetAllInfo<Users>().Any(e => e.ID == id); 133 } 134 } 135 }
是不是和EF挺像的,就是GetAllList<T>这个方法有点丑,待我想到好方法,再改进一下,据说EF不是用反射,用的是泛型,我今天大致看了一下源码,确实是这样的,挺好的应该,毕竟反射对性能损失是较大的。
待我研究出来头绪了,再和大家分享。
git地址:https://github.com/1483523635/MyEntityFramework
测试的Git地址:https://github.com/1483523635/UseMyEntityFrameWork