当前位置: 首页 > 工具软件 > FluentData > 使用案例 >

用fluentdata+webform做一个简单项目(2)-FluentData核心功能

濮彬
2023-12-01

选择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();
        }

实现的功能有限,用于说明fluentdata的部分原理,希望能抛砖引玉

 类似资料: