在第一篇《一步步實現本身的ORM(一)》裏,咱們用反射獲取類名、屬性和值,咱們用這些信息開發了簡單的INSERT方法,在上一篇文章裏咱們提到主鍵爲何沒有設置成自增加類型,單單從屬性裏咱們沒法識別哪一個是主鍵,今天咱們用Attribute來標識列,關於Attribute,引用MSDN裏描述html
MADN的定義爲:公共語言運行時容許添加相似關鍵字的描述聲明,叫作attributes, 它對程序中的元素進行標註,如類型、字段、方法和屬性等。Attributes和Microsoft .NET Framework文件的元數據(metadata)保存在一塊兒,能夠用來向運行時描述你的代碼,或者在程序運行的時候影響應用程序的行爲。 咱們簡單的總結爲:定製特性attribute,本質上是一個類,其爲目標元素提供關聯附加信息,並在運行期以反射的方式來獲取附加信息。 sql
簡單來講Attribute就是描述類、方法、屬性參數等信息的。數據庫
可參考《淺析C#中的Attribute》ide
在這裏咱們定義2個Attribute,用來描述表和字段。ui
[AttributeUsage(AttributeTargets.Class)] class TableAttribute : Attribute { /// <summary> /// 表名 /// </summary> public string Name { get; private set; } public TableAttribute(string name) { this.Name = name; } } [AttributeUsage(AttributeTargets.Property)] class ColumnAttribute : Attribute { /// <summary> /// 是否爲數據庫自動生成 /// </summary> public bool IsGenerated { get; set; } /// <summary> /// 列名 /// </summary> public string Name { get; private set; } public ColumnAttribute(string name) { this.Name = name; } }
修改後的實體類以下:this
[Table("tb_Users")] public class User { [Column("UserId",IsGenerated = true)] public int UserId { get; set; } [Column("Email")] public string Email { get; set; } [Column("CreatedTime")] public DateTime CreatedTime { get; set; } }
咱們把表結構也修改下spa
CREATE TABLE [dbo].[tb_Users]( [UserId] [int] NOT NULL identity(1,1) PRIMARY KEY , [Email] [nvarchar](100) NULL, [CreatedTime] [datetime] NULL)
下面的問題,就是咱們如何獲得表名和字段名呢?咱們仍是採用反射來實現,先獲取表名:3d
TableAttribute[] tableAttr = (TableAttribute[])typeof(User).GetCustomAttributes(typeof(TableAttribute), true); if (tableAttr.Length>0) { Console.WriteLine(tableAttr[0].Name); }
運行結果code
再獲取列名,先查找property,而後找Attribute,代碼以下:htm
var properties = typeof(User).GetProperties(); for (int i = 0; i < properties.Length; i++) { var pi = properties[i]; var columnAttrs = (ColumnAttribute[])pi.GetCustomAttributes(typeof(ColumnAttribute), true); if (columnAttrs.Length>0) { Console.WriteLine("字段名:{0},是否爲自動生成:{1}", columnAttrs[0].Name, columnAttrs[0].IsGenerated); } }
運行結果
再來修改INSERT 方法以下:
public static int Insert(User user) { var type = typeof(User); Dictionary<string, object> parameters = new Dictionary<string, object>(); var properties = type.GetProperties(); string tableName = string.Empty; TableAttribute[] tableAttrs = (TableAttribute[])typeof(User).GetCustomAttributes(typeof(TableAttribute), true); if (tableAttrs.Length > 0) { tableName = tableAttrs[0].Name; } else { tableName = type.Name; } /*將全部的列放到集合裏*/ List<ColumnAttribute> columns = new List<ColumnAttribute>(); for (int i = 0; i < properties.Length; i++) { var pi = properties[i]; var attrs = (ColumnAttribute[])pi.GetCustomAttributes(typeof(ColumnAttribute), true); if (attrs.Length > 0) { columns.Add(attrs[0]); } } StringBuilder sql = new StringBuilder(); sql.Append("INSERT INTO [").Append(tableName).Append("]("); int paramIndex = 0; for (int i = 0; i < properties.Length; i++) { var pi = properties[i]; var attrs = (ColumnAttribute[])pi.GetCustomAttributes(typeof(ColumnAttribute), true); if (attrs.Length > 0 && attrs[0].IsGenerated == false) { if (paramIndex > 0) sql.Append(","); sql.Append(attrs[0].Name); paramIndex++; } } sql.Append(") VALUES ("); paramIndex = 0; for (int i = 0; i < properties.Length; i++) { var pi = properties[i]; var attrs = (ColumnAttribute[])pi.GetCustomAttributes(typeof(ColumnAttribute), true); if (attrs.Length > 0 && attrs[0].IsGenerated == false) { if (paramIndex > 0) sql.Append(","); sql.Append("@p").Append(paramIndex); parameters.Add("@p" + paramIndex, pi.GetValue(user, null)); paramIndex++; } } sql.Append(")"); Console.WriteLine(sql); SqlConnection conn = new SqlConnection(connectionString); var cmd = conn.CreateCommand(); cmd.CommandText = sql.ToString(); foreach (var item in parameters) { var pa = cmd.CreateParameter(); pa.ParameterName = item.Key; pa.Value = item.Value ?? DBNull.Value; cmd.Parameters.Add(pa); } conn.Open(); return cmd.ExecuteNonQuery(); }
運行結果
咱們再定義一個IdAttribute 類用來表示主鍵,它不須要任何屬性
[AttributeUsage(AttributeTargets.Property)] class IdAttribute :ColumnAttribute { public IdAttribute(string name) : base(name) { } }
有了主鍵咱們下面能夠寫UPDATE和DELETE 方法:
UPDATE:
public static int Update(User user) { var type = typeof(User); Dictionary<string, object> parameters = new Dictionary<string, object>(); var properties = type.GetProperties(); string tableName = string.Empty; TableAttribute[] tableAttrs = (TableAttribute[])typeof(User).GetCustomAttributes(typeof(TableAttribute), true); if (tableAttrs.Length > 0) { tableName = tableAttrs[0].Name; } else { tableName = type.Name; } StringBuilder sql = new StringBuilder(); sql.Append("UPDATE [").Append(tableName).Append("] SET "); int paramIndex = 0; for (int i = 0; i < properties.Length; i++) { var pi = properties[i]; var idAttrs = (IdAttribute[])pi.GetCustomAttributes(typeof(IdAttribute), true); if (idAttrs.Length > 0) //若是是主鍵 跳過 continue; var columnAttrs = (ColumnAttribute[])pi.GetCustomAttributes(typeof(ColumnAttribute), true); if (columnAttrs.Length > 0) { if (paramIndex > 0) sql.Append(","); // 字段 = @p sql.Append(columnAttrs[0].Name).Append("=").Append("@p" + paramIndex); /*參數*/ parameters.Add("@p" + paramIndex, pi.GetValue(user, null)); paramIndex++; } } sql.Append(" WHERE "); int keyIndex = 0; for (int i = 0; i < properties.Length; i++) { var pi = properties[i]; var idAttrs = (IdAttribute[])pi.GetCustomAttributes(typeof(IdAttribute), true); if (idAttrs.Length > 0) { if (keyIndex > 0) //考慮到有多個主鍵 sql.Append(" AND "); sql.Append(idAttrs[0].Name).Append("=").Append("@p").Append(paramIndex); /*參數*/ parameters.Add("@p" + paramIndex, pi.GetValue(user, null)); paramIndex++; keyIndex++; } } Console.WriteLine(sql); SqlConnection conn = new SqlConnection(connectionString); var cmd = conn.CreateCommand(); cmd.CommandText = sql.ToString(); foreach (var item in parameters) { var pa = cmd.CreateParameter(); pa.ParameterName = item.Key; pa.Value = item.Value ?? DBNull.Value; cmd.Parameters.Add(pa); } conn.Open(); return cmd.ExecuteNonQuery(); }
調用代碼:
Update(new User() { UserId = 1, Email = "new@new.com", CreatedTime = DateTime.Now });
運行結果:
DELETE方法:
public static int DeleteByKey(params object[] values) { var type = typeof(User); Dictionary<string, object> parameters = new Dictionary<string, object>(); var properties = type.GetProperties(); string tableName = string.Empty; TableAttribute[] tableAttrs = (TableAttribute[])typeof(User).GetCustomAttributes(typeof(TableAttribute), true); if (tableAttrs.Length > 0) { tableName = tableAttrs[0].Name; } else { tableName = type.Name; } /*將全部的列放到集合裏*/ List<IdAttribute> columns = new List<IdAttribute>(); for (int i = 0; i < properties.Length; i++) { var pi = properties[i]; var attrs = (IdAttribute[])pi.GetCustomAttributes(typeof(IdAttribute), true); if (attrs.Length > 0) { columns.Add(attrs[0]); } } if (columns.Count != values.Length) throw new ArgumentException("參數個數和主鍵數不一致"); StringBuilder sql = new StringBuilder(); sql.Append("DELETE FROM [").Append(tableName).Append("] ").Append(" WHERE "); for (int i = 0; i < columns.Count; i++) { if (i > 0) //考慮到有多個主鍵 sql.Append(" AND "); sql.Append(columns[i].Name).Append("=").Append("@p").Append(i); /*參數*/ parameters.Add("@p" + i, values[i]); } Console.WriteLine(sql); SqlConnection conn = new SqlConnection(connectionString); var cmd = conn.CreateCommand(); cmd.CommandText = sql.ToString(); foreach (var item in parameters) { var pa = cmd.CreateParameter(); pa.ParameterName = item.Key; pa.Value = item.Value ?? DBNull.Value; cmd.Parameters.Add(pa); } conn.Open(); return cmd.ExecuteNonQuery(); }
調用代碼:
DeleteByKey(1);
運行結果
最後咱們把增刪改方法放在一個泛型類裏。
class EntityHelper { private const string connectionString = ""; public static int Insert<T>(T entity) { var type = typeof(T); Dictionary<string, object> parameters = new Dictionary<string, object>(); var properties = type.GetProperties(); string tableName = string.Empty; TableAttribute[] tableAttrs = (TableAttribute[])type.GetCustomAttributes(typeof(TableAttribute), true); if (tableAttrs.Length > 0) { tableName = tableAttrs[0].Name; } else { tableName = type.Name; } /*將全部的列放到集合裏*/ List<ColumnAttribute> columns = new List<ColumnAttribute>(); for (int i = 0; i < properties.Length; i++) { var pi = properties[i]; var attrs = (ColumnAttribute[])pi.GetCustomAttributes(typeof(ColumnAttribute), true); if (attrs.Length > 0) { columns.Add(attrs[0]); } } StringBuilder sql = new StringBuilder(); sql.Append("INSERT INTO [").Append(tableName).Append("]("); int paramIndex = 0; for (int i = 0; i < properties.Length; i++) { var pi = properties[i]; var attrs = (ColumnAttribute[])pi.GetCustomAttributes(typeof(ColumnAttribute), true); if (attrs.Length > 0 && attrs[0].IsGenerated == false) { if (paramIndex > 0) sql.Append(","); sql.Append(attrs[0].Name); paramIndex++; } } sql.Append(") VALUES ("); paramIndex = 0; for (int i = 0; i < properties.Length; i++) { var pi = properties[i]; var attrs = (ColumnAttribute[])pi.GetCustomAttributes(typeof(ColumnAttribute), true); if (attrs.Length > 0 && attrs[0].IsGenerated == false) { if (paramIndex > 0) sql.Append(","); sql.Append("@p").Append(paramIndex); parameters.Add("@p" + paramIndex, pi.GetValue(entity, null)); paramIndex++; } } sql.Append(")"); Console.WriteLine(sql); SqlConnection conn = new SqlConnection(connectionString); var cmd = conn.CreateCommand(); cmd.CommandText = sql.ToString(); foreach (var item in parameters) { var pa = cmd.CreateParameter(); pa.ParameterName = item.Key; pa.Value = item.Value ?? DBNull.Value; cmd.Parameters.Add(pa); } conn.Open(); return cmd.ExecuteNonQuery(); } public static int Update<T>(T entity) { var type = typeof(T); Dictionary<string, object> parameters = new Dictionary<string, object>(); var properties = type.GetProperties(); string tableName = string.Empty; TableAttribute[] tableAttrs = (TableAttribute[])type.GetCustomAttributes(typeof(TableAttribute), true); if (tableAttrs.Length > 0) { tableName = tableAttrs[0].Name; } else { tableName = type.Name; } StringBuilder sql = new StringBuilder(); sql.Append("UPDATE [").Append(tableName).Append("] SET "); int paramIndex = 0; for (int i = 0; i < properties.Length; i++) { var pi = properties[i]; var idAttrs = (IdAttribute[])pi.GetCustomAttributes(typeof(IdAttribute), true); if (idAttrs.Length > 0) //若是是主鍵 跳過 continue; var columnAttrs = (ColumnAttribute[])pi.GetCustomAttributes(typeof(ColumnAttribute), true); if (columnAttrs.Length > 0) { if (paramIndex > 0) sql.Append(","); // 字段 = @p sql.Append(columnAttrs[0].Name).Append("=").Append("@p" + paramIndex); /*參數*/ parameters.Add("@p" + paramIndex, pi.GetValue(entity, null)); paramIndex++; } } sql.Append(" WHERE "); int keyIndex = 0; for (int i = 0; i < properties.Length; i++) { var pi = properties[i]; var idAttrs = (IdAttribute[])pi.GetCustomAttributes(typeof(IdAttribute), true); if (idAttrs.Length > 0) { if (keyIndex > 0) //考慮到有多個主鍵 sql.Append(" AND "); sql.Append(idAttrs[0].Name).Append("=").Append("@p").Append(paramIndex); /*參數*/ parameters.Add("@p" + paramIndex, pi.GetValue(entity, null)); paramIndex++; keyIndex++; } } Console.WriteLine(sql); SqlConnection conn = new SqlConnection(connectionString); var cmd = conn.CreateCommand(); cmd.CommandText = sql.ToString(); foreach (var item in parameters) { var pa = cmd.CreateParameter(); pa.ParameterName = item.Key; pa.Value = item.Value ?? DBNull.Value; cmd.Parameters.Add(pa); } conn.Open(); return cmd.ExecuteNonQuery(); } public static int DeleteByKey<T>(params object[] values) { var type = typeof(T); Dictionary<string, object> parameters = new Dictionary<string, object>(); var properties = type.GetProperties(); string tableName = string.Empty; TableAttribute[] tableAttrs = (TableAttribute[])type.GetCustomAttributes(typeof(TableAttribute), true); if (tableAttrs.Length > 0) { tableName = tableAttrs[0].Name; } else { tableName = type.Name; } /*將全部的列放到集合裏*/ List<IdAttribute> columns = new List<IdAttribute>(); for (int i = 0; i < properties.Length; i++) { var pi = properties[i]; var attrs = (IdAttribute[])pi.GetCustomAttributes(typeof(IdAttribute), true); if (attrs.Length > 0) { columns.Add(attrs[0]); } } if (columns.Count != values.Length) throw new ArgumentException("參數個數和主鍵數不一致"); StringBuilder sql = new StringBuilder(); sql.Append("DELETE FROM [").Append(tableName).Append("] ").Append(" WHERE "); for (int i = 0; i < columns.Count; i++) { if (i > 0) //考慮到有多個主鍵 sql.Append(" AND "); sql.Append(columns[i].Name).Append("=").Append("@p").Append(i); /*參數*/ parameters.Add("@p" + i, values[i]); } Console.WriteLine(sql); SqlConnection conn = new SqlConnection(connectionString); var cmd = conn.CreateCommand(); cmd.CommandText = sql.ToString(); foreach (var item in parameters) { var pa = cmd.CreateParameter(); pa.ParameterName = item.Key; pa.Value = item.Value ?? DBNull.Value; cmd.Parameters.Add(pa); } conn.Open(); return cmd.ExecuteNonQuery(); } }
大功告成,咱們修改下調用代碼
EntityHelper.Insert(new User() { Email = "abc@123.com", CreatedTime = DateTime.Now }); EntityHelper.Update(new User() { UserId = 1, Email = "new@new.com", CreatedTime = DateTime.Now }); EntityHelper.DeleteByKey<User>(1);