选择FluentData,主要看中其可以自动将sql查询结果映射为指定对象。
举个例子来讲:
public class Deal
{
public int DealId { get; set; }
public string Title { get; set; }
public int FKProviderid { get; set; }
public virtual Provider Provider { get; set; }
}
public class Provider
{
public int ProviderId { get; set; }
public string Name { get; set; }
}
使用FluentData如下的语句:
DbContext.Sql("select a.*,b.Name as Provider_Name from Deal a inner join Provider b on a.FKProviderId=b.ProviderId").QueryMany<Deal>();
返回一个List<Deal>并且每个Deal对象的Provider属性都会自动创建为Provider对象,并且为对象的Name赋值
FluentData可以下载到源码,但代码太多不好理解,我在下面实现了sqldatareader映射的功能,大概可以体现FluentData的实现方式:
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Web;
/// <summary>
/// 反射辅助类
/// </summary>
public static class ReflectionHelper
{
private static readonly ConcurrentDictionary<Type, Dictionary<string, PropertyInfo>> _cachedProperties
= new ConcurrentDictionary<Type, Dictionary<string, PropertyInfo>>();
public static object GetPropertyValue(object item, PropertyInfo property)
{
var value = property.GetValue(item, null);
return value;
}
public static Dictionary<string, PropertyInfo> GetProperties(Type type)
{
var properties = _cachedProperties.GetOrAdd(type, BuildPropertyDictionary);
return properties;
}
private static Dictionary<string, PropertyInfo> BuildPropertyDictionary(Type type)
{
var result = new Dictionary<string, PropertyInfo>();
var properties = type.GetProperties();
foreach (var property in properties)
{
result.Add(property.Name.ToLower(), property);
}
return result;
}
/// <summary>
/// 判断是否是集合
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public static bool IsList(object item)
{
if (item is ICollection)
return true;
return false;
}
/// <summary>
/// 是否Nullable
/// </summary>
/// <param name="property"></param>
/// <returns></returns>
public static bool IsNullable(PropertyInfo property)
{
if (property.PropertyType.IsGenericType &&
property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
return true;
return false;
}
/// <summary>
/// Includes a work around for getting the actual type of a Nullable type.
/// 获取属性的类型,若参数可空,返回实际类型。
/// 注:若参数可空,返回如下形式:System.Nullable`1[System.Int32],通过GetGenericArguments()函数获取数组的第一个值即为实际类型
/// </summary>
public static Type GetPropertyType(PropertyInfo property)
{
if (IsNullable(property))
return property.PropertyType.GetGenericArguments()[0];
return property.PropertyType;
}
/// <summary>
/// 创建实例
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static object GetDefault(Type type)
{
if (type.IsValueType)
return Activator.CreateInstance(type);
return null;
}
/// <summary>
/// 判断是否是枚举类型,基元类型、值类型、文本类型、日期类型
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static bool IsBasicClrType(Type type)
{
if (type.IsEnum
|| type.IsPrimitive
|| type.IsValueType
|| type == typeof(string)
|| type == typeof(DateTime))
return true;
return false;
}
/// <summary>
/// 是否是自定义实体类型
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static bool IsCustomEntity<T>()
{
var type = typeof(T);
if (type.IsClass && Type.GetTypeCode(type) == TypeCode.Object)
return true;
return false;
}
/// <summary>
/// 获取类型的属性信息
/// </summary>
/// <param name="type"></param>
/// <param name="refresh"></param>
/// <returns></returns>
public static Dictionary<string, PropertyInfo> GetProperties(Type type, bool refresh)
{
try
{
Dictionary<string, PropertyInfo> dicts = new Dictionary<string, PropertyInfo>();
if (!_cachedProperties.TryGetValue(type, out dicts))
{
PropertyInfo[] pis = type.GetProperties();
Dictionary<string, PropertyInfo> dict = new Dictionary<string, PropertyInfo>();
foreach (var pi in pis)
{
dict.Add(pi.Name, pi);
}
_cachedProperties.TryAdd(type, dict);
_cachedProperties.TryGetValue(type, out dicts);
}
return dicts;
}
catch (Exception ex)
{
throw new ArgumentException("获取属性列表失败:" + ex.Message);
}
}
/// <summary>
/// sdr转换为属性值
/// </summary>
/// <param name="o"></param>
/// <param name="pi"></param>
/// <param name="sdr"></param>
public static void ConvertType<T>(T t, SqlDataReader sdr)
{
try
{
Type type = typeof(T);
var pis = GetProperties(type, false);
List<PropertyInfo> infos = new List<PropertyInfo>();
List<string> subInfos = new List<string>();
for (int i = 0; i < sdr.FieldCount; i++)
{
string colName = sdr.GetName(i).Trim();
PropertyInfo pi;
if (colName.Contains("_"))
{
subInfos.Add(colName);
colName = colName.Substring(0, colName.IndexOf("_"));
}
if (pis.TryGetValue(colName, out pi))
{
infos.Add(pi);
}
}
foreach (var p in infos)
{
if (IsBasicClrType(p.PropertyType))
{
if (sdr[p.Name] != null)
{
if (sdr[p.Name] != DBNull.Value)
{
p.SetValue(t, Convert.ChangeType(sdr[p.Name], GetPropertyType(p)), null);
}
}
}
else
{
Type ty = GetPropertyType(p);
var sub = ConvertType(ty, sdr, p.PropertyType.Name, subInfos);
p.SetValue(t, Convert.ChangeType(sub, ty), null);
}
}
}
catch(Exception ex)
{
throw new ArgumentException("无法映射属性,属性和sql语句中的字段名称不符:" + ex.Message);
}
}
/// <summary>
/// sdr转换为子属性值
/// </summary>
/// <param name="o"></param>
/// <param name="pi"></param>
/// <param name="sdr"></param>
/// <param name="prefix"></param>
public static object ConvertType(Type type, SqlDataReader sdr, string prefix, List<string> cols)
{
try
{
var pi = GetProperties(type, false);
var obj = Activator.CreateInstance(type);
foreach (var p in pi)
{
var coln = prefix + "_" + p.Value.Name;
if (cols.Contains(coln))
{
if (sdr[coln] != DBNull.Value)
{
p.Value.SetValue(obj, Convert.ChangeType(sdr[coln], p.Value.PropertyType), null);
}
}
}
return obj;
}
catch
{
throw new ArgumentException("无法映射属性,属性和sql语句中的字段名称不符");
}
}
}
using (SqlConnection conn = new SqlConnection("Data Source=.;Initial Catalog=xxxxxx;Persist Security Info=True;User ID=xxxxx;Password=xxxx"))
{
string sql = "select a.Title,b.Name as Provider_Name from Deal a left join Provider b on a.FKProviderId=b.ProviderId";
SqlCommand sc = new SqlCommand(sql, conn);
List<Deal> deals = new List<Deal>();
conn.Open();
SqlDataReader reader = sc.ExecuteReader();
while (reader.Read())
{
Deal deal = new Deal();
ReflectionHelper.ConvertType<Deal>(deal, reader);
deals.Add(deal);
}
reader.Close();
GridView1.DataSource = deals;
GridView1.DataBind();
}