2016新年伊始,望眼過去,不知不覺在博客園已經註冊8個月啦,因爲最近忙於工做,博客遲遲沒有更新。直到最近一直研究.Net設計模式,對一些模式有所感悟,故拿出本身的心得與你們分享,在接下來的全部博客中我都會以【理論介紹】和【具體實踐】兩個方面來敘述對模式的應用。數據庫
倉儲(Respository)是存在於工做單元和數據庫之間單獨分離出來的一層,是對數據訪問的封裝。其優勢:設計模式
1)業務層不須要知道它的具體實現,達到了分離關注點。this
2)提升了對數據庫訪問的維護,對於倉儲的改變並不會改變業務的邏輯,數據庫能夠用Sql Server(該系列博客使用)、MySql等。spa
首先,建立IRepository.cs接口定義對數據操做的契約(命令執行、重載不一樣查詢結果集合、查詢實體、查詢返回結果值)。設計
1 /// <summary> 2 /// Ado.Net實現的倉儲 3 /// </summary> 4 public interface IRepository 5 { 6 /// <summary> 7 /// 增、刪、改對象 8 /// </summary> 9 /// <param name="commandText">Sql語句</param> 10 /// <param name="parameters">參數</param> 11 /// <param name="isCommit">是否提交</param> 12 /// <returns></returns> 13 void Command(string commandText, IDictionary<string, object> parameters = null); 14 15 /// <summary> 16 /// 查詢對象集合 17 /// </summary> 18 /// <typeparam name="T">返回值的實體類型</typeparam> 19 /// <param name="commandText">Sql語句</param> 20 /// <param name="parameters">參數</param> 21 /// <param name="isCommit">是否提交</param> 22 /// <returns>泛型實體集合</returns> 23 List<T> QueryAll<T>(string commandText, IDictionary<string, object> parameters = null) where T : class, new(); 24 25 /// <summary> 26 /// 查詢對象集合 27 /// </summary> 28 /// <param name="commandText"></param> 29 /// <param name="type"></param> 30 /// <param name="parameters"></param> 31 /// <param name="isCommit"></param> 32 /// <returns></returns> 33 List<object> QueryAll(string commandText, Type type, IDictionary<string, object> parameters = null); 34 35 /// <summary> 36 /// 查詢對象 37 /// </summary> 38 /// <typeparam name="TEntity"></typeparam> 39 /// <param name="commandText"></param> 40 /// <param name="type"></param> 41 /// <param name="parameters"></param> 42 /// <returns></returns> 43 T Query<T>(string commandText, IDictionary<string, object> parameters = null) where T : class,new(); 44 45 /// <summary> 46 /// 查詢數量 47 /// </summary> 48 /// <param name="commandText"></param> 49 /// <param name="parameters"></param> 50 /// <returns></returns> 51 object QueryCount(string commandText, IDictionary<string, object> parameters = null); 52 }
其次,定義抽象類BaseRepository.cs實現倉儲。code
1 /// <summary> 2 /// 基礎庫實現 3 /// </summary> 4 public abstract class BaseRepository : IRepository 5 { 6 /// <summary> 7 /// 數據庫鏈接字符串標識 8 /// </summary> 9 public abstract string Key { get; } 10 11 private SqlConnection connection; 12 13 private SqlConnection Connection 14 { 15 get 16 { 17 if (connection == null) 18 { 19 ConnectionStringSettings settings = ConfigurationManager.ConnectionStrings[Key]; 20 connection = new SqlConnection(settings.ConnectionString); 21 } 22 return connection; 23 } 24 } 25 26 /// <summary> 27 /// 增、刪、改命令 28 /// </summary> 29 /// <param name="commandText"></param> 30 /// <param name="parameters"></param> 31 public virtual void Command(string commandText, IDictionary<string, object> parameters = null) 32 { 33 Func<SqlCommand, int> excute = (commend) => 34 { 35 return commend.ExecuteNonQuery(); 36 }; 37 CreateDbCommondAndExcute<int>(commandText, parameters, excute); 38 } 39 40 /// <summary> 41 /// 查詢實體(強類型) 42 /// </summary> 43 /// <typeparam name="T"></typeparam> 44 /// <param name="commandText"></param> 45 /// <param name="parameters"></param> 46 /// <returns></returns> 47 public virtual T Query<T>(string commandText, IDictionary<string, object> parameters = null,Func<IDataReader, T> load = null) where T : class, new() 48 { 49 Func<SqlCommand, T> excute = (dbCommand) => 50 { 51 52 var result = default(T); 53 using (IDataReader reader = dbCommand.ExecuteReader()) 54 { 55 while (reader.Read()) 56 { 57 if (load == null) 58 { 59 load = (s) => { return s.GetReaderData<T>(); }; 60 } 61 result = load(reader); 62 } 63 return result; 64 } 65 }; 66 return CreateDbCommondAndExcute<T>(commandText, parameters, excute); 67 } 68 69 /// <summary> 70 /// 查詢匿名對象集合 71 /// </summary> 72 /// <param name="commandText"></param> 73 /// <param name="type"></param> 74 /// <param name="parameters"></param> 75 /// <returns></returns> 76 public virtual List<object> QueryAll(string commandText, Type type, IDictionary<string, object> parameters = null,Action<dynamic> setItem = null) 77 { 78 Func<SqlCommand, List<object>> excute = (dbCommand) => 79 { 80 var result = new List<object>(); 81 82 using (IDataReader dataReader = dbCommand.ExecuteReader()) 83 { 84 while (dataReader.Read()) 85 { 86 var item = dataReader.GetReaderData(type); 87 if (setItem != null) 88 { 89 setItem(item); 90 } 91 result.Add(item); 92 } 93 } 94 return result; 95 }; 96 return CreateDbCommondAndExcute<List<object>>(commandText, parameters, 97 excute); 98 } 99 100 /// <summary> 101 /// 查詢強類型對象集合 102 /// </summary> 103 /// <typeparam name="T"></typeparam> 104 /// <param name="commandText"></param> 105 /// <param name="parameters"></param> 106 /// <returns></returns> 107 public virtual List<T> QueryAll<T>(string commandText, IDictionary<string, object> parameters = null,Func<IDataReader, T> load = null) where T : class, new() 108 { 109 Func<SqlCommand, List<T>> excute = (dbCommand) => 110 { 111 List<T> result = new List<T>(); 112 using (IDataReader reader = dbCommand.ExecuteReader()) 113 { 114 while (reader.Read()) 115 { 116 if (load == null) 117 { 118 load = (s) => { return s.GetReaderData<T>(); }; 119 } 120 var item = load(reader); 121 result.Add(item); 122 } 123 return result; 124 } 125 }; 126 return CreateDbCommondAndExcute(commandText, parameters, excute); 127 } 128 129 /// <summary> 130 /// 查詢結果數量 131 /// </summary> 132 /// <param name="commandText"></param> 133 /// <param name="parameters"></param> 134 /// <returns></returns> 135 public virtual object QueryCount(string commandText, IDictionary<string, object> parameters = null) 136 { 137 Func<SqlCommand, object> excute = (dbCommand) => 138 { 139 return dbCommand.ExecuteScalar(); 140 }; 141 return CreateDbCommondAndExcute(commandText, parameters, excute); 142 } 143 144 /// <summary> 145 /// 建立命令並執行 146 /// </summary> 147 /// <typeparam name="TValue"></typeparam> 148 /// <param name="commandText"></param> 149 /// <param name="parameters"></param> 150 /// <param name="excute"></param> 151 /// <returns></returns> 152 private TValue CreateDbCommondAndExcute<TValue>(string commandText, 153 IDictionary<string, object> parameters, Func<SqlCommand, TValue> excute) 154 { 155 if (Connection.State == ConnectionState.Closed) { Connection.Open(); }; 156 using (SqlCommand command = new SqlCommand()) 157 { 158 command.CommandType = CommandType.Text; 159 command.CommandText = commandText;; 160 command.Connection = Connection; 161 command.SetParameters(parameters); 162 return excute(command); 163 } 164 } 165 166 /// <summary> 167 /// 關閉鏈接 168 /// </summary> 169 public void Dispose() 170 { 171 if (connection != null) 172 { 173 Connection.Dispose();//非託管資源 174 } 175 } 176 }
最後,實現方法中的擴展方法。對象
1 /// <summary> 2 /// Sql Server 擴展類 3 /// </summary> 4 public static class SqlServerExtension 5 { 6 /// <summary> 7 /// 設置參數 8 /// </summary> 9 /// <param name="dbCommand"></param> 10 /// <param name="parameters"></param> 11 public static void SetParameters(this IDbCommand dbCommand, IDictionary<string, object> parameters) 12 { 13 if (parameters == null) 14 { 15 return; 16 } 17 foreach (var parameter in parameters) 18 { 19 if (parameter.Value != null) 20 { 21 dbCommand.Parameters.Add(new SqlParameter(parameter.Key, parameter.Value)); 22 } 23 else 24 { 25 dbCommand.Parameters.Add(new SqlParameter(parameter.Key,DBNull.Value)); 26 } 27 } 28 } 29 30 /// <summary> 31 /// 獲取對應的實體 32 /// </summary> 33 /// <typeparam name="TEntity"></typeparam> 34 /// <param name="TEntity"></param> 35 /// <returns></returns> 36 public static TEntity GetReaderData<TEntity>(this IDataReader reader) where TEntity : class, new() 37 { 38 var item = new TEntity(); 39 var filedList = new List<string>(); 40 for (int i = 0; i < reader.FieldCount; i++) 41 { 42 filedList.Add(reader.GetName(i)); 43 } 44 //映射數據庫中的字段到實體屬性 45 IEnumerable<PropertyInfo> propertys = typeof(TEntity).GetProperties().Where(s => filedList.Contains(s.Name)); 46 foreach (var property in propertys) 47 { 48 //對實體屬性進行設值 49 property.SetValue(item, reader[property.Name]); 50 } 51 return item; 52 } 53 54 /// <summary> 55 /// 根據列名獲取值 56 /// </summary> 57 /// <typeparam name="T"></typeparam> 58 /// <param name="reader"></param> 59 /// <param name="columnName"></param> 60 /// <returns></returns> 61 public static T GetValue<T>(this IDataReader reader, string columnName) 62 { 63 int index = reader.GetOrdinal(columnName); 64 if (reader.IsDBNull(index)) 65 { 66 return default(T); 67 } 68 return (T)reader[index]; 69 } 70 71 /// <summary> 72 /// 獲取對應的實體 73 /// </summary> 74 /// <param name="reader"></param> 75 /// <param name="type"></param> 76 /// <returns></returns> 77 public static object GetReaderData(this IDataReader reader,Type type) 78 { 79 var item = Activator.CreateInstance(type); 80 var filedList = new List<string>(); 81 for (int i = 0; i < reader.FieldCount; i++) 82 { 83 filedList.Add(reader.GetName(i).ToLower()); 84 } 85 var properties = (from s in type.GetProperties() 86 let name = s.Name.ToLower().Split(new string[] { "_" }, StringSplitOptions.RemoveEmptyEntries).LastOrDefault() 87 where filedList.Contains(s.Name) 88 select new 89 { 90 Name = s.Name, 91 Property = s 92 }).ToList(); 93 94 foreach (var property in properties) 95 { 96 property.Property.SetValue(item, reader[property.Name]); 97 } 98 return item; 99 } 100 }
至此,使用Ado.Net 實現的倉儲完成啦!固然這只是非泛型版本。當須要使用ORM時,該系列會同步更新泛型版本的實現對聚合類的持久化操做的倉儲模式。blog
相信各位廣大園友看到這裏,必定不難看出這和DAL層好像沒什麼區別,沒錯,對於非泛型的倉儲實現等同於DAL層。有人可能會認爲這是一種多餘的設計,對於未使用ORM的數據存儲來講,這裏也就只是提供一種額外的設計思路罷了。接口
在接下來的一篇中將實現數據訪問邏輯和領域層徹底解耦。資源