1. 程式人生 > >.Net設計模式之倉儲(Repository)模式

.Net設計模式之倉儲(Repository)模式

轉自: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/

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面