这几天学习反射的应用,今天把其应用到数据操作中
现记录学习笔记
环境为:
编译器:vs2017
数据库:access
反射类型为:字段
1先在类文件的定义是用哪种数据库,和用字段还是属性来反射
本例是:Access数据库+反射字段
#define OLEDB_ //access数据库 #define FIELDS_ //反射字段
2.定义数据库操作类的别名,用来区分数据库操作要用的函数
定义是反射的是字段还是反射的是属性
//区分是用哪种数据库 #if OLEDB_ //access using MyConnection = OleDbConnection; using MyCommand = OleDbCommand; using MyDataAdapter = OleDbDataAdapter; using MyCommandBuilder = OleDbCommandBuilder; using MyParameter = OleDbParameter; using MyDataRead = OleDbDataReader; //... #elif SQL_ //sql using MyCommand = SqlCommand; using MyConnectin = SqlConnection; using MyDataAdapter = SqlDataAdapter; using MyCommandBuilder = SqlCommandBuilder; using MyParameter = SqlParameter; using MyDataRead = SqlDataReader; //.... #endif //区分是用类的字段还是类的属性, #if FIELDS_ using MyInfo = FieldInfo;//字段 #elif POPRS_ using MyInfo = PropertyInfo;//属性 #endif
3.在类中定义方法来选择反射的样式
//单表模板操作类
//T 为和数据库中要操作的表一样的类或结构体
//可以反射属性,也可以反射字段
class BDAdo<T>
{
/// <summary> /// 获得属性列表,或是字段列表 /// </summary> /// <returns></returns> private MyInfo[] GetInfos() { #if FIELDS_ //字段 return typeof(T).GetFields(); #elif POPRS_ //属性 return typeof(T).GetProperties(); #endif }
}
下面就是在类的各种操作的实现
4.获得查询结果的表
/// <summary> /// 查询指定条件的列表数据 /// </summary> /// <param name="findsql"> 指定查询条件,为NULL就查询全部数据</param> /// <returns></returns> public DataTable GetDataTable(string findsql = null)//查询条件字符串,也就是Sql语句查询的 where 后面的条件语句 { Type ty = typeof(T); // string fName = string.Join(",", ty.GetFields().Select(p => p.Name)); string sql = $"select * from [{ty.Name}]"; if (findsql != null) sql += $" where {findsql}"; DataTable dt = new DataTable(); conn = new MyConnection(conStr); MyDataAdapter da = new MyDataAdapter(sql, conn); try { da.Fill(dt); return dt; } finally { conn.Close(); da.Dispose(); } }
5.添加数据
/// <summary> /// 插入数据 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="t"></param> /// <returns></returns> public bool InsertData(T t) { //获得对象的类型 Type ty = t.GetType(); //拼接添加数据的Sql语句 string intoSql = $"INSERT INTO [{ty.Name}] ({GetFildeNames()}) VALUES ({GetFileParams()})"; conn = new MyConnection(conStr); MyCommand cmd = conn.CreateCommand(); cmd.CommandText = intoSql; cmd.Parameters.AddRange(GetParameters(t)); try { conn.Open(); return cmd.ExecuteNonQuery() == 1; } finally { cmd.Dispose(); conn.Close(); } }
6 根据字段或是属性获得参数化列表
/// <summary> /// 获得参数化列表 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="t"></param> /// <returns></returns> private MyParameter[] GetParameters(T t) { Type ty = typeof(T); List<MyParameter> parList = new List<MyParameter>(); foreach (var v in GetInfos()) { MyParameter pr = new MyParameter($"@{v.Name}", v.GetValue(t)); parList.Add(pr); } return parList.ToArray(); }
7.获得字段或是属性名称组成的字符串
/// <summary> /// 获得类的字段名或属性名,组成的字符串 /// </summary> /// <param name="ty"></param> /// <returns></returns> private string GetFildeNames() { Type ty = typeof(T); return string.Join(",", GetInfos().Select(p => $"[{p.Name}]")); }
样式:
name,sex,age,tel,adds
8.获得字段或是属性名称组成的参数格式字符串
/// <summary> /// 获得类的字段名或是属性名,并以参数化样式(@name)组成的字符串 /// </summary> /// <param name="ty"></param> /// <returns></returns> private string GetFileParams() { Type ty = typeof(T); return string.Join(",", GetInfos().Select(p => $"@{p.Name}")); }
//样式:
@name,@sex,@age,@tel,@adds
9.对数据库的增,删,改,执行命令
1可以是Sql语句操作,
2也可以是参数化列表操作,
3也可以是储存过程操作
/// <summary> /// Sql语句执行命令(insert,delete,update) /// </summary> /// <param name="sql"></param> /// <param name="cmdType"></param> /// <param name="pars"></param> /// <returns></returns> public int ExecuteNonQuery(string sql, CommandType cmdType = CommandType.Text, params MyParameter[] pars) { conn = new MyConnection(conStr); MyCommand cmd = conn.CreateCommand(); cmd.CommandType = cmdType; cmd.CommandText = sql; if (pars.Length > 0) { cmd.Parameters.Clear(); cmd.Parameters.AddRange(pars); } try { conn.Open(); return cmd.ExecuteNonQuery(); } finally { conn.Close(); cmd.Dispose(); } }
10.查询指定条件,返回一个对象实例
/// <summary> /// 查询指定条件的对象 /// </summary> /// <param name="cxSql"></param> /// <returns></returns> public T FindOneObject(string cxSql) { Type ty = typeof(T); //string sql = $"select {GetFildeNames()} from {ty.Name} where {cxSql}"; object obj = Activator.CreateInstance(ty); DataTable dt = GetDataTable(cxSql); if (dt.Rows.Count == 0) return default(T); foreach (var v in GetInfos()) { SetObjectValue(v, dt.Rows[0][$"{v.Name}"], ref obj); } return (T)obj; }
SetObjectValue()
/// <summary> /// 设置字段或是属性相应的值 /// </summary> /// <param name="v">属性或是字段</param> /// <param name="value">要设置的值</param> /// <param name="obj">要设置的对象</param> private void SetObjectValue(MyInfo v, object value, ref object obj) { string name =null;//获得字段或是属性的数据类型名称,用来给相应的数据类型赋值 #if POPRS_ //属性 name = v.PropertyType.Name; #elif FIELDS_ //字段 name=v.FieldType.Name; #endif switch (name) { case "Int32": //int v.SetValue(obj, int.Parse(value.ToString())); break; ; case "String": //string v.SetValue(obj, value.ToString()); break; case "Double": //double v.SetValue(obj, double.Parse(value.ToString())); break; case "Object"://object v.SetValue(obj, value); break; case "Boolean"://bool v.SetValue(obj, bool.Parse(value.ToString())); break; case "Char"://char v.SetValue(obj, char.Parse(value.ToString())); break; case "Byte[]"://byte[] if(value!=DBNull.Value) v.SetValue(obj, (byte[])value);//强转为字节数组 break; default: //其他类型,以后用的时候再加上 throw new Exception("没有指定转换的类型!!!"); } }
11.用法
在要用的类中声明一个静态对象
public class MyApp
{
public static BDAdo<TXL_TABLE> Ado { get => new BDAdo<TXL_TABLE>();/* set => ado = value;*/ }
}
示例1:添加数据
TXL_TABLE tt = new TXL_TABLE(); tt.ID = int.Parse(txtID.Text); tt.TName = txtName.Text; tt.Sex = txtSex.Text; tt.Age=int.Parse(txtAge.Text); tt.FenZu = txtFenZu.Text; tt.Tel = txtTel.Text; byte[] tem = { 0 }; if (picImage.Image != null) tt.Image = MyApp.Ado.ImageToByte(picImage.Image); else tt.Image = tem; bool bRet = MyApp.Ado.InsertData(tt); if(bRet) { MessageBox.Show("添加成功") }
示例2:修改数据
TXL_TABLE tt = new TXL_TABLE(); tt.ID = int.Parse(txtID.Text); tt.TName = txtName.Text; tt.Sex = txtSex.Text; tt.Age=int.Parse(txtAge.Text); tt.FenZu = txtFenZu.Text; tt.Tel = txtTel.Text; byte[] tem = { 0 }; if (picImage.Image != null) tt.Image = MyApp.Ado.ImageToByte(picImage.Image); else tt.Image = tem; if( MyApp.Ado.UpdateData($"ID={oldID}", tt)>0) MessageBox.Show("修改成功");
示例3:查找单个对象
int id = (int)Tag; TXL_TABLE tt= MyApp.Ado.FindOneObject($"ID={id}");
//......