.Net設計模式之倉儲(Repository)模式
阿新 • • 發佈:2018-11-01
轉自:http://www.cnblogs.com/retop/
.Net設計模式之倉儲(Repository)模式
理論介紹
倉儲(Respository)是存在於工作單元和資料庫之間單獨分離出來的一層,是對資料訪問的封裝。其優點:
1)業務層不需要知道它的具體實現,達到了分離關注點。
2)提高了對資料庫訪問的維護,對於倉儲的改變並不會改變業務的邏輯,資料庫可以用Sql Server(該系列部落格使用)、MySql等。
具體實踐
首先,建立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實現倉儲。
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時,該系列會同步更新泛型版本的實現對聚合類的持久化操作的倉儲模式。
後記
相信各位廣大園友看到這裡,一定不難看出這和DAL層好像沒什麼區別,沒錯,對於非泛型的倉儲實現等同於DAL層。有人可能會認為這是一種多餘的設計,對於未使用ORM的資料儲存來說,這裡也就只是提供一種額外的設計思路罷了。
在接下來的一篇中將實現資料訪問邏輯和領域層完全解耦。
作者:摯誠v8
出處:http://www.cnblogs.com/retop/
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面