說明:此篇文章是給那些和我一樣仍在使用ADO.NET訪問數據庫的.NET開發人員寫的,因為某些原因,比如還在使用.NET3.0以下版本開發.NET應用或者所使用的數據庫對ORM支持不是很好,或者是對ORM的性能有所懷疑(其實在訪問量不是很大的情況下沒有必要過分追求性能的極限)等等,這部分人仍在使用傳統的ADO.NET來訪問數據庫,他們或手寫或采用代碼生成工具來生成實體類和增刪改查的SQL語句,在將DataTable或者DataReader轉換成對應的實體類的時候仍需要一行行寫代碼,本類就是為了解決這個問題的,可以用幾個類來實現方便快捷的轉換。本類庫在SQL Server/MySQL/SQLite下測試通過,由於條件有限未在所有的數據庫下測試,如果有問題請在此留言或者在周公的微博留言(http://weibo.com/zhoufoxcn)。
其實在寫這套類庫之前,去年周公就寫了兩篇有關的文章,一篇叫《用C#打造自己的實體轉換器》,另一篇叫《利用ADO.NET的體系架構打造通用的數據庫訪問通用類》,本篇的代碼就是在這兩篇文章的基礎上經過實際應用修改而成,主要是修正了幾個問題:1.如果在SELECT子句的字段中不包含對應實體類的某個屬性,那么該屬性的值就為它對應Type的默認值(如int,short為0,引用類型為null),而不是像以前那樣用Ignorable,因為有些屬性可能在某個查詢中需要而在另外一個查詢中不需要,采用Ignorable這樣的Attribute的話太武斷;2.修正了在泛型類型時的錯誤;3.在類的屬性類型中除了支持常見數據類型(數值類型、可空類型和string)之外,還支持byte[]這種常見的數據類型。
本類庫共有5個類:DbProviderType、ProviderFactory、DbUtility、EntityReader、ColumnNameAttribute。
其中DbProviderType、ProviderFactory、DbUtility三個類的相關代碼如下:
- using System;
- using System.Collections.Generic;
- using System.Data;
- using System.Data.Common;
- namespace NetSkycn.Data
- {
- /// <summary>
- /// 通用數據庫訪問類,封裝了對數據庫的常見操作
- /// 作者:周公
- /// 創建日期:2011-07-18
- /// 修改日期:2012-04-12
- /// 新浪微博地址:http://weibo.com/zhoufoxcn
- /// </summary>
- public sealed class DbUtility
- {
- public string ConnectionString { get; set; }
- private DbProviderFactory providerFactory;
- /// <summary>
- /// 構造函數
- /// </summary>
- /// <param name="connectionString">數據庫連接字符串</param>
- /// <param name="providerType">數據庫類型枚舉,參見<paramref name="providerType"/></param>
- public DbUtility(string connectionString, DbProviderType providerType)
- {
- ConnectionString = connectionString;
- providerFactory = ProviderFactory.GetDbProviderFactory(providerType);
- if (providerFactory == null)
- {
- throw new ArgumentException("Can't load DbProviderFactory for given value of providerType");
- }
- }
- /// <summary>
- /// 對數據庫執行增刪改操作,返回受影響的行數。
- /// </summary>
- /// <param name="sql">要執行的增刪改的SQL語句</param>
- /// <param name="parameters">執行增刪改語句所需要的參數</param>
- /// <returns></returns>
- public int ExecuteNonQuery(string sql, IList<DbParameter> parameters)
- {
- return ExecuteNonQuery(sql, parameters, CommandType.Text);
- }
- /// <summary>
- /// 對數據庫執行增刪改操作,返回受影響的行數。
- /// </summary>
- /// <param name="sql">要執行的增刪改的SQL語句</param>
- /// <param name="parameters">執行增刪改語句所需要的參數</param>
- /// <param name="commandType">執行的SQL語句的類型</param>
- /// <returns></returns>
- public int ExecuteNonQuery(string sql, IList<DbParameter> parameters, CommandType commandType)
- {
- using (DbCommand command = CreateDbCommand(sql, parameters, commandType))
- {
- command.Connection.Open();
- int affectedRows = command.ExecuteNonQuery();
- command.Connection.Close();
- return affectedRows;
- }
- }
- /// <summary>
- /// 執行一個查詢語句,返回一個關聯的DataReader實例
- /// </summary>
- /// <param name="sql">要執行的查詢語句</param>
- /// <param name="parameters">執行SQL查詢語句所需要的參數</param>
- /// <returns></returns>
- public DbDataReader ExecuteReader(string sql, IList<DbParameter> parameters)
- {
- return ExecuteReader(sql, parameters, CommandType.Text);
- }
- /// <summary>
- /// 執行一個查詢語句,返回一個關聯的DataReader實例
- /// </summary>
- /// <param name="sql">要執行的查詢語句</param>
- /// <param name="parameters">執行SQL查詢語句所需要的參數</param>
- /// <param name="commandType">執行的SQL語句的類型</param>
- /// <returns></returns>
- public DbDataReader ExecuteReader(string sql, IList<DbParameter> parameters, CommandType commandType)
- {
- DbCommand command = CreateDbCommand(sql, parameters, commandType);
- command.Connection.Open();
- return command.ExecuteReader(CommandBehavior.CloseConnection);
- }
- /// <summary>
- /// 執行一個查詢語句,返回一個包含查詢結果的DataTable
- /// </summary>
- /// <param name="sql">要執行的查詢語句</param>
- /// <param name="parameters">執行SQL查詢語句所需要的參數</param>
- /// <returns></returns>
- public DataTable ExecuteDataTable(string sql, IList<DbParameter> parameters)
- {
- return ExecuteDataTable(sql, parameters, CommandType.Text);
- }
- /// <summary>
- /// 執行一個查詢語句,返回一個包含查詢結果的DataTable
- /// </summary>
- /// <param name="sql">要執行的查詢語句</param>
- /// <param name="parameters">執行SQL查詢語句所需要的參數</param>
- /// <param name="commandType">執行的SQL語句的類型</param>
- /// <returns></returns>
- public DataTable ExecuteDataTable(string sql, IList<DbParameter> parameters, CommandType commandType)
- {
- using (DbCommand command = CreateDbCommand(sql, parameters, commandType))
- {
- using (DbDataAdapter adapter = providerFactory.CreateDataAdapter())
- {
- adapter.SelectCommand = command;
- DataTable data = new DataTable();
- adapter.Fill(data);
- return data;
- }
- }
- }
- /// <summary>
- /// 執行一個查詢語句,返回查詢結果的第一行第一列
- /// </summary>
- /// <param name="sql">要執行的查詢語句</param>
- /// <param name="parameters">執行SQL查詢語句所需要的參數</param>
- /// <returns></returns>
- public Object ExecuteScalar(string sql, IList<DbParameter> parameters)
- {
- return ExecuteScalar(sql, parameters, CommandType.Text);
- }
- /// <summary>
- /// 執行一個查詢語句,返回查詢結果的第一行第一列
- /// </summary>
- /// <param name="sql">要執行的查詢語句</param>
- /// <param name="parameters">執行SQL查詢語句所需要的參數</param>
- /// <param name="commandType">執行的SQL語句的類型</param>
- /// <returns></returns>
- public Object ExecuteScalar(string sql, IList<DbParameter> parameters, CommandType commandType)
- {
- using (DbCommand command = CreateDbCommand(sql, parameters, commandType))
- {
- command.Connection.Open();
- object result = command.ExecuteScalar();
- command.Connection.Close();
- return result;
- }
- }
- /// <summary>
- /// 查詢多個實體集合
- /// </summary>
- /// <typeparam name="T">返回的實體集合類型</typeparam>
- /// <param name="sql">要執行的查詢語句</param>
- /// <param name="parameters">執行SQL查詢語句所需要的參數</param>
- /// <returns></returns>
- public List<T> QueryForList<T>(string sql, IList<DbParameter> parameters) where T : new()
- {
- return QueryForList<T>(sql, parameters, CommandType.Text);
- }
- /// <summary>
- /// 查詢多個實體集合
- /// </summary>
- /// <typeparam name="T">返回的實體集合類型</typeparam>
- /// <param name="sql">要執行的查詢語句</param>
- /// <param name="parameters">執行SQL查詢語句所需要的參數</param>
- /// <param name="commandType">執行的SQL語句的類型</param>
- /// <returns></returns>
- public List<T> QueryForList<T>(string sql, IList<DbParameter> parameters, CommandType commandType) where T : new()
- {
- DataTable data = ExecuteDataTable(sql, parameters, commandType);
- return EntityReader.GetEntities<T>(data);
- }
- /// <summary>
- /// 查詢單個實體
- /// </summary>
- /// <typeparam name="T">返回的實體集合類型</typeparam>
- /// <param name="sql">要執行的查詢語句</param>
- /// <param name="parameters">執行SQL查詢語句所需要的參數</param>
- /// <returns></returns>
- public T QueryForObject<T>(string sql, IList<DbParameter> parameters) where T : new()
- {
- return QueryForObject<T>(sql, parameters, CommandType.Text);
- }
- /// <summary>
- /// 查詢單個實體
- /// </summary>
- /// <typeparam name="T">返回的實體集合類型</typeparam>
- /// <param name="sql">要執行的查詢語句</param>
- /// <param name="parameters">執行SQL查詢語句所需要的參數</param>
- /// <param name="commandType">執行的SQL語句的類型</param>
- /// <returns></returns>
- public T QueryForObject<T>(string sql, IList<DbParameter> parameters, CommandType commandType) where T : new()
- {
- List <T> list= QueryForList<T>(sql, parameters, commandType);
- if (list.Count > 0)
- {
- return list[0];
- }
- else
- {
- return default(T);
- }
- }
- public DbParameter CreateDbParameter(string name, object value)
- {
- return CreateDbParameter(name, ParameterDirection.Input, value);
- }
- public DbParameter CreateDbParameter(string name, ParameterDirection parameterDirection, object value)
- {
- DbParameter parameter = providerFactory.CreateParameter();
- parameter.ParameterName = name;
- parameter.Value = value;
- parameter.Direction = parameterDirection;
- return parameter;
- }
- /// <summary>
- /// 創建一個DbCommand對象
- /// </summary>
- /// <param name="sql">要執行的查詢語句</param>
- /// <param name="parameters">執行SQL查詢語句所需要的參數</param>
- /// <param name="commandType">執行的SQL語句的類型</param>
- /// <returns></returns>
- private DbCommand CreateDbCommand(string sql, IList<DbParameter> parameters, CommandType commandType)
- {
- DbConnection connection = providerFactory.CreateConnection();
- DbCommand command = providerFactory.CreateCommand();
- connection.ConnectionString = ConnectionString;
- command.CommandText = sql;
- command.CommandType = commandType;
- command.Connection = connection;
- if (!(parameters == null || parameters.Count == 0))
- {
- foreach (DbParameter parameter in parameters)
- {
- command.Parameters.Add(parameter);
- }
- }
- return command;
- }
- }
- /// <summary>
- /// 數據庫類型枚舉
- /// </summary>
- public enum DbProviderType : byte
- {
- SqlServer,
- MySql,
- SQLite,
- Oracle,
- ODBC,
- OleDb,
- Firebird,
- PostgreSql,
- DB2,
- Informix,
- SqlServerCe
- }
- /// <summary>
- /// DbProviderFactory工廠類
- /// </summary>
- public class ProviderFactory
- {
- private static Dictionary<DbProviderType, string> providerInvariantNames = new Dictionary<DbProviderType, string>();
- private static Dictionary<DbProviderType, DbProviderFactory> providerFactoies = new Dictionary<DbProviderType, DbProviderFactory>(20);
- static ProviderFactory()
- {
- //加載已知的數據庫訪問類的程序集
- providerInvariantNames.Add(DbProviderType.SqlServer, "System.Data.SqlClient");
- providerInvariantNames.Add(DbProviderType.OleDb, "System.Data.OleDb");
- providerInvariantNames.Add(DbProviderType.ODBC, "System.Data.ODBC");
- providerInvariantNames.Add(DbProviderType.Oracle, "Oracle.DataAccess.Client");
- providerInvariantNames.Add(DbProviderType.MySql, "MySql.Data.MySqlClient");
- providerInvariantNames.Add(DbProviderType.SQLite, "System.Data.SQLite");
- providerInvariantNames.Add(DbProviderType.Firebird, "FirebirdSql.Data.Firebird");
- providerInvariantNames.Add(DbProviderType.PostgreSql, "Npgsql");
- providerInvariantNames.Add(DbProviderType.DB2, "IBM.Data.DB2.iSeries");
- providerInvariantNames.Add(DbProviderType.Informix, "IBM.Data.Informix");
- providerInvariantNames.Add(DbProviderType.SqlServerCe, "System.Data.SqlServerCe");
- }
- /// <summary>
- /// 獲取指定數據庫類型對應的程序集名稱
- /// </summary>
- /// <param name="providerType">數據庫類型枚舉</param>
- /// <returns></returns>
- public static string GetProviderInvariantName(DbProviderType providerType)
- {
- return providerInvariantNames[providerType];
- }
- /// <summary>
- /// 獲取指定類型的數據庫對應的DbProviderFactory
- /// </summary>
- /// <param name="providerType">數據庫類型枚舉</param>
- /// <returns></returns>
- public static DbProviderFactory GetDbProviderFactory(DbProviderType providerType)
- {
- //如果還沒有加載,則加載該DbProviderFactory
- if (!providerFactoies.ContainsKey(providerType))
- {
- providerFactoies.Add(providerType, ImportDbProviderFactory(providerType));
- }
- return providerFactoies[providerType];
- }
- /// <summary>
- /// 加載指定數據庫類型的DbProviderFactory
- /// </summary>
- /// <param name="providerType">數據庫類型枚舉</param>
- /// <returns></returns>
- private static DbProviderFactory ImportDbProviderFactory(DbProviderType providerType)
- {
- string providerName = providerInvariantNames[providerType];
- DbProviderFactory factory = null;
- try
- {
- //從全局程序集中查找
- factory = DbProviderFactories.GetFactory(providerName);
- }
- catch (ArgumentException e)
- {
- factory = null;
- }
- return factory;
- }
- }
- }
其中EntityReader、ColumnNameAttribute的代碼如下:
- using System;
- using System.Collections.Generic;
- using System.Data;
- using System.Data.Common;
- using System.Reflection;
- namespace NetSkycn.Data
- {
- /// <summary>
- /// 實體閱讀器類,可以從DataTable中或者DbDataReader的實例中將數據轉換成對應的示例
- /// 作者:周公
- /// 創建日期:2011-07-21
- /// 修改日期:2012-04-12
- /// 新浪微博地址:http://weibo.com/zhoufoxcn
- /// </summary>
- public sealed class EntityReader
- {
- private const BindingFlags BindingFlag = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
- //將類型與該類型所有的可寫且未被忽略屬性之間建立映射
- private static Dictionary<Type, Dictionary<string, PropertyInfo>> propertyMappings = new Dictionary<Type, Dictionary<string, PropertyInfo>>();
- /// <summary>
- /// 將DataTable中的所有數據轉換成List>T<集合
- /// </summary>
- /// <typeparam name="T">DataTable中每條數據可以轉換的數據類型</typeparam>
- /// <param name="dataTable">包含有可以轉換成數據類型T的數據集合</param>
- /// <returns></returns>
- public static List<T> GetEntities<T>(DataTable dataTable) where T : new()
- {
- if (dataTable == null)
- {
- throw new ArgumentNullException("dataTable");
- }
- //如果T的類型滿足以下條件:字符串、ValueType或者是Nullable<ValueType>
- if (typeof(T) == typeof(string)||typeof(T)==typeof(byte[])|| typeof(T).IsValueType)
- {
- return GetSimpleEntities<T>(dataTable);
- }
- else
- {
- return GetComplexEntities<T>(dataTable);
- }
- }
- /// <summary>
- /// 將DbDataReader中的所有數據轉換成List>T<集合
- /// </summary>
- /// <typeparam name="T">DbDataReader中每條數據可以轉換的數據類型</typeparam>
- /// <param name="dataTable">包含有可以轉換成數據類型T的DbDataReader實例</param>
- /// <returns></returns>
- public static List<T> GetEntities<T>(DbDataReader reader) where T : new()
- {
- List<T> list = new List<T>();
- if (reader == null)
- {
- throw new ArgumentNullException("reader");
- }
- //如果T的類型滿足以下條件:字符串、ValueType或者是Nullable<ValueType>
- if (typeof(T) == typeof(string) || typeof(T).IsValueType)
- {
- return GetSimpleEntities<T>(reader);
- }
- else
- {
- return GetComplexEntities<T>(reader);
- }
- }
- /// <summary>
- /// 從DataTable中將每一行的第一列轉換成T類型的數據
- /// </summary>
- /// <typeparam name="T">要轉換的目標數據類型</typeparam>
- /// <param name="dataTable">包含有可以轉換成數據類型T的數據集合</param>
- /// <returns></returns>
- private static List<T> GetSimpleEntities<T>(DataTable dataTable) where T : new()
- {
- List<T> list = new List<T>();
- foreach (DataRow row in dataTable.Rows)
- {
- list.Add((T)GetValueFromObject(row[0], typeof(T)));
- }
- return list;
- }
- /// <summary>
- /// 將指定的 Object 的值轉換為指定類型的值。
- /// </summary>
- /// <param name="value">實現 IConvertible 接口的 Object,或者為 null</param>
- /// <param name="targetType">要轉換的目標數據類型</param>
- /// <returns></returns>
- private static object GetValueFromObject(object value, Type targetType)
- {
- if (targetType == typeof(string))//如果要將value轉換成string類型
- {
- return GetString(value);
- }
- else if(targetType==typeof(byte[]))//如果要將value轉換成byte[]類型
- {
- return GetBinary(value);
- }
- else if (targetType.IsGenericType)//如果目標類型是泛型
- {
- return GetGenericValueFromObject(value, targetType);
- }
- else//如果是基本數據類型(包括數值類型、枚舉和Guid)
- {
- return GetNonGenericValueFromObject(value, targetType);
- }
- }
- /// <summary>
- /// 從DataTable中讀取復雜數據類型集合
- /// </summary>
- /// <typeparam name="T">要轉換的目標數據類型</typeparam>
- /// <param name="dataTable">包含有可以轉換成數據類型T的數據集合</param>
- /// <returns></returns>
- private static List<T> GetComplexEntities<T>(DataTable dataTable) where T : new()
- {
- if (!propertyMappings.ContainsKey(typeof(T)))
- {
- GenerateTypePropertyMapping(typeof(T));
- }
- List<T> list = new List<T>();
- Dictionary<string, PropertyInfo> properties = propertyMappings[typeof(T)];
- T t;
- foreach (DataRow row in dataTable.Rows)
- {
- t = new T();
- foreach (KeyValuePair<string, PropertyInfo> item in properties)
- {
- //如果對應的屬性名出現在數據源的列中則獲取值並設置給對應的屬性
- if (row[item.Key] != null)
- {
- item.Value.SetValue(t, GetValueFromObject(row[item.Key], item.Value.PropertyType), null);
- }
- }
- list.Add(t);
- }
- return list;
- }
- /// <summary>
- /// 從DbDataReader的實例中讀取復雜的數據類型
- /// </summary>
- /// <typeparam name="T">要轉換的目標類</typeparam>
- /// <param name="reader">DbDataReader的實例</param>
- /// <returns></returns>
- private static List<T> GetComplexEntities<T>(DbDataReader reader) where T : new()
- {
- if (!propertyMappings.ContainsKey(typeof(T)))//檢查當前是否已經有該類與類的可寫屬性之間的映射
- {
- GenerateTypePropertyMapping(typeof(T));
- }
- List<T> list = new List<T>();
- Dictionary<string, PropertyInfo> properties = propertyMappings[typeof(T)];
- T t;
- while (reader.Read())
- {
- t = new T();
- foreach (KeyValuePair<string, PropertyInfo> item in properties)
- {
- //如果對應的屬性名出現在數據源的列中則獲取值並設置給對應的屬性
- if (reader[item.Key] != null)
- {
- item.Value.SetValue(t, GetValueFromObject(reader[item.Key], item.Value.PropertyType), null);
- }
- }
- list.Add(t);
- }
- return list;
- }
- /// <summary>
- /// 從DbDataReader的實例中讀取簡單數據類型(String,ValueType)
- /// </summary>
- /// <typeparam name="T">目標數據類型</typeparam>
- /// <param name="reader">DbDataReader的實例</param>
- /// <returns></returns>
- private static List<T> GetSimpleEntities<T>(DbDataReader reader)
- {
- List<T> list = new List<T>();
- while (reader.Read())
- {
- list.Add((T)GetValueFromObject(reader[0], typeof(T)));
- }
- return list;
- }
- /// <summary>
- /// 將Object轉換成字符串類型
- /// </summary>
- /// <param name="value">object類型的實例</param>
- /// <returns></returns>
- private static object GetString(object value)
- {
- return Convert.ToString(value);
- }
- /// <summary>
- /// 將指定的 Object 的值轉換為指定枚舉類型的值。
- /// </summary>
- /// <param name="value">實現 IConvertible 接口的 Object,或者為 null</param>
- /// <param name="targetType"></param>
- /// <returns></returns>
- private static object GetEnum(object value, Type targetType)
- {
- return Enum.Parse(targetType, value.ToString());
- }
- /// <summary>
- /// 將指定的 Object 的值轉換為指定枚舉類型的值。
- /// </summary>
- /// <param name="value">實現 IConvertible 接口的 Object,或者為 null</param>
- /// <returns></returns>
- private static object GetBoolean(object value)
- {
- if (value is Boolean)
- {
- return value;
- }
- else
- {
- byte byteValue = (byte)GetByte(value);
- if (byteValue == 0)
- {
- return false;
- }
- else
- {
- return true;
- }
- }
- }
- /// <summary>
- /// 將指定的 Object 的值轉換為指定枚舉類型的值。
- /// </summary>
- /// <param name="value">實現 IConvertible 接口的 Object,或者為 null</param>
- /// <returns></returns>
- private static object GetByte(object value)
- {
- if (value is Byte)
- {
- return value;
- }
- else
- {
- return byte.Parse(value.ToString());
- }
- }
- /// <summary>
- /// 將指定的 Object 的值轉換為指定枚舉類型的值。
- /// </summary>
- /// <param name="value">實現 IConvertible 接口的 Object,或者為 null</param>
- /// <returns></returns>
- private static object GetSByte(object value)
- {
- if (value is SByte)
- {
- return value;
- }
- else
- {
- return SByte.Parse(value.ToString());
- }
- }
- /// <summary>
- /// 將指定的 Object 的值轉換為指定枚舉類型的值。
- /// </summary>
- /// <param name="value">實現 IConvertible 接口的 Object,或者為 null</param>
- /// <returns></returns>
- private static object GetChar(object value)
- {
- if (value is Char)
- {
- return value;
- }
- else
- {
- return Char.Parse(value.ToString());
- }
- }
- /// <summary>
- /// 將指定的 Object 的值轉換為指定枚舉類型的值。
- /// </summary>
- /// <param name="value">實現 IConvertible 接口的 Object,或者為 null</param>
- /// <returns></returns>
- private static object GetGuid(object value)
- {
- if (value is Guid)
- {
- return value;
- }
- else
- {
- return new Guid(value.ToString());
- }
- }
- /// <summary>
- /// 將指定的 Object 的值轉換為指定枚舉類型的值。
- /// </summary>
- /// <param name="value">實現 IConvertible 接口的 Object,或者為 null</param>
- /// <returns></returns>
- private static object GetInt16(object value)
- {
- if (value is Int16)
- {
- return value;
- }
- else
- {
- return Int16.Parse(value.ToString());
- }
- }
- /// <summary>
- /// 將指定的 Object 的值轉換為指定枚舉類型的值。
- /// </summary>
- /// <param name="value">實現 IConvertible 接口的 Object,或者為 null</param>
- /// <returns></returns>
- private static object GetUInt16(object value)
- {
- if (value is UInt16)
- {
- return value;
- }
- else
- {
- return UInt16.Parse(value.ToString());
- }
- }
- /// <summary>
- /// 將指定的 Object 的值轉換為指定枚舉類型的值。
- /// </summary>
- /// <param name="value">實現 IConvertible 接口的 Object,或者為 null</param>
- /// <returns></returns>
- private static object GetInt32(object value)
- {
- if (value is Int32)
- {
- return value;
- }
- else
- {
- return Int32.Parse(value.ToString());
- }
- }
- /// <summary>
- /// 將指定的 Object 的值轉換為指定枚舉類型的值。
- /// </summary>
- /// <param name="value">實現 IConvertible 接口的 Object,或者為 null</param>
- /// <returns></returns>
- private static object GetUInt32(object value)
- {
- if (value is UInt32)
- {
- return value;
- }
- else
- {
- return UInt32.Parse(value.ToString());
- }
- }
- /// <summary>
- /// 將指定的 Object 的值轉換為指定枚舉類型的值。
- /// </summary>
- /// <param name="value">實現 IConvertible 接口的 Object,或者為 null</param>
- /// <returns></returns>
- private static object GetInt64(object value)
- {
- if (value is Int64)
- {
- return value;
- }
- else
- {
- return Int64.Parse(value.ToString());
- }
- }
- /// <summary>
- /// 將指定的 Object 的值轉換為指定枚舉類型的值。
- /// </summary>
- /// <param name="value">實現 IConvertible 接口的 Object,或者為 null</param>
- /// <returns></returns>
- private static object GetUInt64(object value)
- {
- if (value is UInt64)
- {
- return value;
- }
- else
- {
- return UInt64.Parse(value.ToString());
- }
- }
- /// <summary>
- /// 將指定的 Object 的值轉換為指定枚舉類型的值。
- /// </summary>
- /// <param name="value">實現 IConvertible 接口的 Object,或者為 null</param>
- /// <returns></returns>
- private static object GetSingle(object value)
- {
- if (value is Single)
- {
- return value;
- }
- else
- {
- return Single.Parse(value.ToString());
- }
- }
- /// <summary>
- /// 將指定的 Object 的值轉換為指定枚舉類型的值。
- /// </summary>
- /// <param name="value">實現 IConvertible 接口的 Object,或者為 null</param>
- /// <returns></returns>
- private static object GetDouble(object value)
- {
- if (value is Double)
- {
- return value;
- }
- else
- {
- return Double.Parse(value.ToString());
- }
- }
- /// <summary>
- /// 將指定的 Object 的值轉換為指定枚舉類型的值。
- /// </summary>
- /// <param name="value">實現 IConvertible 接口的 Object,或者為 null</param>
- /// <returns></returns>
- private static object GetDecimal(object value)
- {
- if (value is Decimal)
- {
- return value;
- }
- else
- {
- return Decimal.Parse(value.ToString());
- }
- }
- /// <summary>
- /// 將指定的 Object 的值轉換為指定枚舉類型的值。
- /// </summary>
- /// <param name="value">實現 IConvertible 接口的 Object,或者為 null</param>
- /// <returns></returns>
- private static object GetDateTime(object value)
- {
- if (value is DateTime)
- {
- return value;
- }
- else
- {
- return DateTime.Parse(value.ToString());
- }
- }
- /// <summary>
- /// 將指定的 Object 的值轉換為指定枚舉類型的值。
- /// </summary>
- /// <param name="value">實現 IConvertible 接口的 Object,或者為 null</param>
- /// <returns></returns>
- private static object GetTimeSpan(object value)
- {
- if (value is TimeSpan)
- {
- return value;
- }
- else
- {
- return TimeSpan.Parse(value.ToString());
- }
- }
- /// <summary>
- /// 將指定的 Object 的值轉換為指定枚舉類型的值。
- /// </summary>
- /// <param name="value">實現 IConvertible 接口的 Object,或者為 null</param>
- /// <returns></returns>
- private static byte[] GetBinary(object value)
- {
- //如果該字段為NULL則返回null
- if (value == DBNull.Value)
- {
- return null;
- }
- else if (value is Byte[])
- {
- return (byte[])(value);
- }
- else
- {
- return null;
- }
- }
- /// <summary>
- /// 將Object類型數據轉換成對應的可空數值類型表示
- /// </summary>
- /// <param name="value">實現 IConvertible 接口的 Object,或者為 null</param>
- /// <param name="targetType">可空數值類型</param>
- /// <returns></returns>
- private static object GetGenericValueFromObject(object value, Type targetType)
- {
- if (value == DBNull.Value)
- {
- return null;
- }
- else
- {
- //獲取可空數值類型對應的基本數值類型,如int?->int,long?->long
- //Type nonGenericType = genericTypeMappings[targetType];
- Type nonGenericType = targetType.GetGenericArguments()[0];
- return GetNonGenericValueFromObject(value, nonGenericType);
- }
- }
- /// <summary>
- /// 將指定的 Object 的值轉換為指定類型的值。
- /// </summary>
- /// <param name="value">實現 IConvertible 接口的 Object,或者為 null</param>
- /// <param name="targetType">目標對象的類型</param>
- /// <returns></returns>
- private static object GetNonGenericValueFromObject(object value, Type targetType)
- {
- if (targetType.IsEnum)//因為
- {
- return GetEnum(value, targetType);
- }
- else
- {
- switch (targetType.Name)
- {
- case "Byte": return GetByte(value);
- case "SByte": return GetSByte(value);
- case "Char": return GetChar(value);
- case "Boolean": return GetBoolean(value);
- case "Guid": return GetGuid(value);
- case "Int16": return GetInt16(value);
- case "UInt16": return GetUInt16(value);
- case "Int32": return GetInt32(value);
- case "UInt32": return GetUInt32(value);
- case "Int64": return GetInt64(value);
- case "UInt64": return GetUInt64(value);
- case "Single": return GetSingle(value);
- case "Double": return GetDouble(value);
- case "Decimal": return GetDecimal(value);
- case "DateTime": return GetDateTime(value);
- case "TimeSpan": return GetTimeSpan(value);
- default: return null;
- }
- }
- }
- /// <summary>
- /// 獲取該類型中屬性與數據庫字段的對應關系映射
- /// </summary>
- /// <param name="type"></param>
- private static void GenerateTypePropertyMapping(Type type)
- {
- if (type != null)
- {
- PropertyInfo[] properties = type.GetProperties(BindingFlag);
- Dictionary<string, PropertyInfo> propertyColumnMapping = new Dictionary<string, PropertyInfo>(properties.Length);
- string description = string.Empty;
- Attribute[] attibutes = null;
- string columnName = string.Empty;
- foreach (PropertyInfo p in properties)
- {
- columnName = string.Empty;
- attibutes = Attribute.GetCustomAttributes(p);
- foreach (Attribute attribute in attibutes)
- {
- //檢查是否設置了ColumnName屬性
- if (attribute.GetType() == typeof(ColumnNameAttribute))
- {
- columnName = ((ColumnNameAttribute)attribute).ColumnName;
- break;
- }
- }
- //如果該屬性是可讀並且未被忽略的,則有可能在實例化該屬性對應的類時用得上
- if (p.CanWrite)
- {
- //如果沒有設置ColumnName屬性,則直接將該屬性名作為數據庫字段的映射
- if (string.IsNullOrEmpty(columnName))
- {
- columnName = p.Name;
- }
- propertyColumnMapping.Add(columnName, p);
- }
- }
- propertyMappings.Add(type, propertyColumnMapping);
- }
- }
- }
- /// <summary>
- /// 自定義屬性,用於指示如何從DataTable或者DbDataReader中讀取類的屬性值
- /// </summary>
- public class ColumnNameAttribute : Attribute
- {
- /// <summary>
- /// 類屬性對應的列名
- /// </summary>
- public string ColumnName { get; set; }
- /// <summary>
- /// 構造函數
- /// </summary>
- /// <param name="columnName">類屬性對應的列名</param>
- public ColumnNameAttribute(string columnName)
- {
- ColumnName = columnName;
- }
- }
- }
注意:因為在machine.config中的<system.data> <DbProviderFactories>已經存在如下內容:
- <system.data>
- <DbProviderFactories>
- <add name="Odbc Data Provider" invariant="System.Data.Odbc" description=".Net Framework Data Provider for Odbc" type="System.Data.Odbc.OdbcFactory, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
- <add name="OleDb Data Provider" invariant="System.Data.OleDb" description=".Net Framework Data Provider for OleDb" type="System.Data.OleDb.OleDbFactory, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
- <add name="OracleClient Data Provider" invariant="System.Data.OracleClient" description=".Net Framework Data Provider for Oracle" type="System.Data.OracleClient.OracleClientFactory, System.Data.OracleClient, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
- <add name="SqlClient Data Provider" invariant="System.Data.SqlClient" description=".Net Framework Data Provider for SqlServer" type="System.Data.SqlClient.SqlClientFactory, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
- <add name="Microsoft SQL Server Compact Data Provider" invariant="System.Data.SqlServerCe.3.5" description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe, Version=3.5.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91" />
- </DbProviderFactories>
- </system.data>
所以如果你采用以上的四種方式之一來訪問數據,那么就不需要采取任何設置,但如果你是訪問其它類型的數據庫(如MySQL,SQLite)那么就需要在當前config文件的根節點下增加<system.data> <DbProviderFactories>節點,並在節點中增加你訪問的數據庫的方式,以下是可能值之一(注意並不是全部,添加時也不不必將下面的配置全部添加進去,只添加你所使用的數據庫對應的方式即可):
- <add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".Net Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" />
- <add name="Informix Data Provider" invariant="IBM.Data.Informix" description=".Net Framework Data Provider for Informix" type="IBM.Data.Informix.IfxFactory, IBM.Data.Informix" />
- <add name="DB2 Data Provider" invariant="IBM.Data.DB2.iSeries" description=".Net Framework Data Provider for DB2 iSeries" type="IBM.Data.DB2.iSeries.DB2Factory, IBM.Data.DB2.iSeries" />
- <add name="Firebird Data Provider" invariant="FirebirdSql.Data.FirebirdClient" description="Firebird" type="FirebirdSql.Data.FirebirdClient.FirebirdClientFactory, FirebirdSql.Data.FirebirdClient"/>
- <add name="Oracle Data Provider" invariant="Oracle.DataAccess.Client" description=".Net Framework Data Provider for Oracle" type="Oracle.DataAccess.Client.OracleClientFactory, Oracle.DataAccess" />
- <add name="PostgreSQL Data Provider Data Provider" invariant="Npgsql" description=".Net Framework Data Provider for PostgreSQL" type="Npgsql.NpgsqlFactory, Npgsql" />
比如在項目中使用了SQLite數據庫,那么有關這部分的配置如下(這里講述可能相當啰嗦,但也是沒辦法的事情,因為周公經常收到詢問此處細節的留言):
- <?xml version="1.0" encoding="utf-8" ?>
- <configuration>
- <system.data>
- <DbProviderFactories>
- <add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".Net Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" />
- </DbProviderFactories>
- </system.data>
- </configuration>
