using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Data;
using System.Data.SqlClient;
namespace ConsoleApplication4
{
public class AutoMapper
{
public delegate string FormatColumnName(string columnName);
/// <summary>
/// 从缓存中取出对象的公共属性,用来解决反射的性能问题
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static PropertyInfo[] GetProperties<T>() where T : class
{
Type t = typeof(T);
string key = string.Format("GetProperties_{0}", t.FullName);
System.Runtime.Caching.MemoryCache cache = System.Runtime.Caching.MemoryCache.Default;
if (cache[key] == null)
{
PropertyInfo[] properties = t.GetProperties();
cache.Add(key, properties, new DateTimeOffset(DateTime.Now.AddMinutes(20)));
return properties;
}
return cache[key] as PropertyInfo[];
}
public static List<string> GetColumnNames(IDataReader dr)
{
return GetColumnNames(dr, null);
}
public static List<string> GetColumnNames(IDataReader dr, FormatColumnName method)
{
List<string> list = new List<string>();
for (int i = 0; i < dr.FieldCount; i++)
{
var fileName = dr.GetName(i);
if (method != null)
{
fileName = method(fileName);
}
list.Add(fileName);
}
return list;
}
/// <summary>
/// 将数据库中的字段名用Pascel命名法则转换成类型的属性名,若有"_"则在"_"处将数据库字段名切割成N个片段,每个片段的首字母大写其余字母小写,将这些片段连接起来组成某个类的属性名
/// </summary>
/// <param name="columnName">columnName名</param>
/// <returns></returns>
private static string ConvertToPascal(string columnName)
{
string[] strArr = columnName.Split('_');
StringBuilder result = new StringBuilder();
foreach (string item in strArr)
{
if (item.Length > 0)
{
result.Append(item.Substring(0, 1).ToUpper());
if (item.Length > 1)
{
result.Append(item.Substring(1).ToLower());
}
}
}
return result.ToString();
}
/// <summary>
/// 将数据库中的字段名用Pascel命名法则转换成类型的属性名,若有"_"则在"_"处将数据库字段名切割成N个片段,每个片段的首字母大写其余字母小写,将这些片段连接起来组成某个类的属性名
/// </summary>
public static readonly FormatColumnName ConvertToPascal2
= columnName =>
{
string[] sArr = columnName.Split('_');
StringBuilder result = new StringBuilder();
foreach (string item in sArr)
{
if (item.Length > 0)
{
result.Append(item.Substring(0, 1).ToUpper());
if (item.Length > 1)
{
result.Append(item.Substring(1).ToLower());
}
}
}
return result.ToString();
};
/// <summary>
/// 将DataReader转换为实体集合
/// </summary>
/// <typeparam name="T">实体类型</typeparam>
/// <param name="dr">数据读取流</param>
/// <param name="method">DataReader的字段名与类型T的属性名之间的转换函数</param>
/// <returns></returns>
public static List<T> DataReaderToModelList<T>(IDataReader dr, FormatColumnName method) where T : class, new()
{
List<T> list = null;
var fieldNames = GetColumnNames(dr, method);
var properties = GetProperties<T>();
while (dr.Read())
{
if (list == null)
{
list = new List<T>();
}
T o = new T();
foreach (var p in properties)
{
var columnName = p.Name;
if (fieldNames.Contains(columnName))
{
if (!Convert.IsDBNull(dr[columnName]))
{
object value = dr[columnName];
if (value.GetType() != p.PropertyType)
{
//如果dr中字段的类型与实体T的属性类型不匹配,则以T的属性类型为准
value = Convert.ChangeType(value, p.PropertyType);
}
p.SetValue(o, value, null);
}
}
}
list.Add(o);
}
return list;
}
/// <summary>
/// 将DataReader转换成类型T
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="dr">DataReader</param>
/// <param name="method">DataReader的字段名与类型T的属性名之间的转换方法,FieldToPropertyMethods类中有几个预定义的静态方法可供使用</param>
/// <returns></returns>
public static T DataReaderToModel<T>(IDataReader dr) where T : class,new()
{
T objectInstance = new T();
PropertyInfo[] properties = GetProperties<T>();
var filedNames = GetColumnNames(dr);
foreach (var p in properties)
{
var columnName = p.Name;
if (filedNames.Contains(columnName))
{
if (!Convert.IsDBNull(dr[columnName]))
{
object value = dr[columnName];
if (value.GetType() != p.PropertyType)
{
//如果dr中字段的类型与实体T的属性类型不匹配,则以T的属性类型为准
value = Convert.ChangeType(value, p.PropertyType);
}
p.SetValue(objectInstance, value, null);
}
}
}
return objectInstance;
}
public static DbType GetDbType(object o)
{
string typeName = o.GetType().Name.ToLower();
DbType dbType;
switch (typeName)
{
case "guid":
dbType = DbType.Guid;
break;
case "short":
dbType = DbType.Int16;
break;
case "byte":
dbType = DbType.Byte;
break;
case "int":
dbType = DbType.Int32;
break;
case "long":
dbType = DbType.Int64;
break;
case "dateTime":
dbType = DbType.DateTime;
break;
case "double":
dbType = DbType.Double;
break;
case "decimal":
dbType = DbType.Decimal;
break;
case "float":
dbType = DbType.Decimal;
break;
case "bool":
dbType = DbType.Boolean;
break;
default:
dbType = DbType.String;
break;
}
return dbType;
}
public static DbType GetDbType2(Type type)
{
TypeCode typeCode = Type.GetTypeCode(type);
DbType dt;
switch (typeCode)
{
case TypeCode.Boolean:
dt = DbType.Boolean;
break;
case TypeCode.Byte:
dt = DbType.Byte;
break;
case TypeCode.Char:
dt = DbType.UInt16;
break;
case TypeCode.DateTime:
dt = DbType.DateTime;
break;
case TypeCode.Decimal:
dt = DbType.Decimal;
break;
case TypeCode.Double:
dt = DbType.Double;
break;
case TypeCode.Int16:
dt = DbType.Int16;
break;
case TypeCode.Int32:
dt = DbType.Int32;
break;
case TypeCode.Int64:
dt = DbType.Int64;
break;
//case TypeCode.Object:
// dt = DbType.Object;
// break;
case TypeCode.SByte:
dt = DbType.SByte;
break;
case TypeCode.Single:
dt = DbType.Single;
break;
case TypeCode.String:
dt = DbType.String;
break;
case TypeCode.UInt16:
dt = DbType.UInt16;
break;
case TypeCode.UInt32:
dt = DbType.UInt32;
break;
case TypeCode.UInt64:
dt = DbType.UInt64;
break;
default:
dt = DbType.Int32;
break;
}
return dt;
}
public SqlParameter[] SqlParameter<T>(T entity) where T:class, new()
{
IList<SqlParameter> sqlParameterList = new List<SqlParameter>();
PropertyInfo[] properties = GetProperties<T>();
foreach (var p in properties)
{
SqlParameter sqlParameter = new SqlParameter();
sqlParameter.ParameterName = string.Format("@{0}", p.Name);
sqlParameter.Value = p.GetValue(entity, null);
sqlParameter.DbType = GetDbType(p.PropertyType);
sqlParameterList.Add(sqlParameter);
}
return sqlParameterList.ToArray();
}
/// <summary>
/// 将DataReader转换为泛型集合
/// </summary>
/// <typeparam naame="T">泛型</typeparam>
/// <param name="dr">DataReader</param>
/// <returns></returns>
private List<T> DataReaderToEntityList<T>(IDataReader dr) where T : class
{
List<T> list = new List<T>();
Type t = typeof(T);
PropertyInfo[] properties = t.GetProperties();
while (dr.Read())
{
T o = Activator.CreateInstance(t) as T;
foreach (PropertyInfo p in properties)
{
if (!Convert.IsDBNull(dr[p.Name]))
{
p.SetValue(o, dr[p.Name], null);
}
}
T e = o as T;
list.Add(e);
}
return list;
}
private List<T> DataReaderToEntityList2<T>(IDataReader dr) where T : class, new()
{
List<T> result = new List<T>();
PropertyInfo[] properties = GetProperties<T>();
List<string> fieldNames = GetColumnNames(dr);
while (dr.Read())
{
T objectInstance = new T();
foreach (var p in properties)
{
var exists = fieldNames.Exists(item => item.Equals(p.Name, StringComparison.OrdinalIgnoreCase));
if (exists)
{
p.SetValue(objectInstance, dr[p.Name], null);
}
}
result.Add(objectInstance);
}
return result;
}
private T DataReaderToEntity<T>(IDataReader dr) where T : class, new()
{
T objectInstance = new T();
PropertyInfo[] properties = GetProperties<T>();
for (int i = 0; i < dr.FieldCount; i++)
{
foreach (var p in properties)
{
if (p.Name == dr.GetName(i))
{
p.SetValue(objectInstance, dr[i], null);
}
}
}
return objectInstance;
}
/// <summary>
/// 映射
/// </summary>
/// <typeparam name="FormT">源类型</typeparam>
/// <typeparam name="ToT">目标类型</typeparam>
/// <param name="formObject">源对象</param>
/// <returns>目标对象</returns>
public static ToT Mapping<FormT, ToT>(FormT formObject)
where FormT : class, new()
where ToT : class, new()
{
//http://blog.csdn.net/cxzhq2002/article/details/8753495
//集合到集合暂没有实现
ToT t = new ToT();
PropertyInfo[] formProperties = GetProperties<FormT>();
PropertyInfo[] toProperties = GetProperties<ToT>();
foreach (var p in toProperties)
{
var exists = formProperties.Where(item => item.Name.Equals(p.Name, StringComparison.OrdinalIgnoreCase));
if (exists.Count() > 0)
{
var value = exists.First().GetValue(formObject, null);
p.SetValue(t, value, null);
}
}
return t;
}
public static IList<V> Mapping<U, V>(IList<U> formList)
where U : class, new()
where V : class, new()
{
//http://blog.csdn.net/cxzhq2002/article/details/8753495
//集合到集合暂没有实现
//轻量的映射工具,不可与ORM做比较。它不参与到DB。一般用来配合SqlHelper/企业库来使用
//作用:1.参数;2.dataReader转为Entity或List,3.对象对象,集合到集合,不支持深嵌套对象。
PropertyInfo[] formProperties = GetProperties<U>();
PropertyInfo[] toProperties = GetProperties<V>();
IList<V> toList = new List<V>();
foreach (var item in formList)
{
V to = new V();
foreach (var p in toProperties)
{
var exists = formProperties.Where(k => k.Name.Equals(p.Name, StringComparison.OrdinalIgnoreCase));
if (exists.Count() > 0)
{
var value = exists.First().GetValue(item, null);
p.SetValue(to, value, null);
}
}
toList.Add(to);
}
return toList;
}
/// <summary>
/// 映射
/// </summary>
/// <typeparam name="FormT">源类型</typeparam>
/// <typeparam name="ToT">目标类型</typeparam>
/// <param name="formObject">源对象</param>
/// <returns>目标对象</returns>
public static void Mapping<FormT, ToT>(FormT formObject, ToT toObject)
where FormT : class, new()
where ToT : class, new()
{
PropertyInfo[] formProperties = GetProperties<FormT>();
PropertyInfo[] toProperties = GetProperties<ToT>();
foreach (var p in toProperties)
{
var index = formProperties.ToList().FindIndex(item => item.Name.Equals(p.Name, StringComparison.OrdinalIgnoreCase));
if (index >= 0)
{
var value = formProperties[index].GetValue(formObject, null);
p.SetValue(toObject, value, null);
}
}
}
}
}
//轻量的映射工具,不可与ORM做比较。它不参与到DB。一般用来配合SqlHelper/企业库来使用
//作用:1.参数;2.dataReader转为Entity或List,3.对象对象,集合到集合,不支持深嵌套对象。
数据库部分参数可借助dynamic来实现必须要的参数(暂时没办法添加值类型)
dynamic student = new { Name = "张三", Gender = true, Age = 25, Birthday = DateTime.Now };
Console.Write(student.GetType());
增加Attibute来实现特殊对映