Mapper 实体转换Entiy to Dto
阅读原文时间:2023年07月10日阅读:1

实际使用中发现很多问题 如果用EFcore 框架,这个表达式树生成一个新的实体
导致EFcore 跟踪失败!

///

/// 生成表达式目录树 泛型缓存 ///
///
///
public class ExpressionGenericMapper//Mapper`2
{
private static Func _FUNC = null;
private static Func _FUNC2 = null;
public static TOut Trans(TIn t)
{
return _FUNC(t);
}

    /// <summary>  
    /// 批量实体转换  
    /// </summary>  
    /// <param name="list">被转换的实体List</param>  
    /// <returns></returns>  
    public static List<TOut> TransList(List<TIn> list)  
    {  
        List<TOut> outs = new List<TOut>();  
        foreach (var item in list)  
        {  
            outs.Add(Trans(item));  
        }  
        return outs;  
    }

    /// <summary>  
    /// 把TOut 按照TIn来更新  
    /// </summary>  
    /// <param name="news"></param>  
    /// <param name="old"></param>  
    /// <returns></returns>  
    public static TOut Modify(TIn news, TOut old)  
    {  
        return \_FUNC2(news, old);  
    }

    static ExpressionGenericMapper()  
    {  
        Type stringType = typeof(string);  
        #region 创建构造对象的委托  
        {  
            ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "m");  
            List<MemberBinding> memberBindingList = new List<MemberBinding>();  
            foreach (var item in typeof(TOut).GetProperties())  
            {  
                var type = typeof(TIn);  
                if (item.PropertyType.IsClass && item.PropertyType != stringType)//排除String以外的引用类型,不进行赋值  
                {  
                    continue;  
                }  
                var prop = type.GetProperty(item.GetMappingName());//从Out类找映射的字段名  
                if (prop != null)//如果TIn里能找到该属性  
                {

                    MemberExpression property = Expression.Property(parameterExpression, prop);  
                    MemberBinding memberBinding = Expression.Bind(item, property);  
                    memberBindingList.Add(memberBinding);  
                }  
            }  
            foreach (var item in typeof(TOut).GetFields())  
            {  
                var type = typeof(TIn);  
                if (item.FieldType.IsClass && item.FieldType != stringType)//排除String以外的引用类型,不进行赋值  
                {  
                    continue;  
                }  
                var prop = type.GetField(item.GetMappingName());//从Out类找映射的字段名  
                if (prop != null)  
                {  
                    MemberExpression property = Expression.Field(parameterExpression, prop);  
                    MemberBinding memberBinding = Expression.Bind(item, property);  
                    memberBindingList.Add(memberBinding);  
                }

            }  
            MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());  
            Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression\[\]  
            {  
                parameterExpression  
            });  
            \_FUNC = lambda.Compile();//拼装是一次性的  
        }  
        #endregion  
        #region 修改对象的委托  
        {

            ParameterExpression oExpression = Expression.Parameter(typeof(TOut), "o");  
            ParameterExpression nExpression = Expression.Parameter(typeof(TIn), "n");  
            List<MemberBinding> memberBindingList = new List<MemberBinding>();  
            foreach (var item in typeof(TOut).GetProperties())  
            {  
                var type = typeof(TIn);  
                if (item.PropertyType.IsClass && item.PropertyType != stringType)//排除String以外的引用类型,不进行赋值  
                {  
                    continue;  
                }  
                var prop = type.GetProperty(item.GetMappingName());  
                if (prop != null)  
                {  
                    MemberExpression property = Expression.Property(nExpression, prop);  
                    MemberBinding memberBinding = Expression.Bind(item, property);  
                    memberBindingList.Add(memberBinding);  
                }  
                else  
                {  
                    var propOld = typeof(TOut).GetProperty(item.Name);  
                    MemberExpression property = Expression.Property(oExpression, propOld);  
                    MemberBinding memberBinding = Expression.Bind(item, property);  
                    memberBindingList.Add(memberBinding);  
                }  
            }  
            foreach (var item in typeof(TOut).GetFields())  
            {  
                var type = typeof(TIn);  
                if (item.FieldType.IsClass && item.FieldType != stringType)//排除String以外的引用类型,不进行赋值  
                {  
                    continue;  
                }  
                var prop = type.GetField(item.GetMappingName());  
                if (prop != null)  
                {  
                    MemberExpression property = Expression.Field(nExpression, prop);  
                    MemberBinding memberBinding = Expression.Bind(item, property);  
                    memberBindingList.Add(memberBinding);  
                }  
                else  
                {  
                    var propOld = typeof(TOut).GetField(item.Name);  
                    MemberExpression property = Expression.Field(oExpression, propOld);  
                    MemberBinding memberBinding = Expression.Bind(item, property);  
                    memberBindingList.Add(memberBinding);  
                }  
            }  
            MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());  
            Expression<Func<TIn, TOut, TOut>> lambda = Expression.Lambda<Func<TIn, TOut, TOut>>(memberInitExpression, new ParameterExpression\[\]  
            {  
               nExpression, oExpression  
            });  
            \_FUNC2 = lambda.Compile();//拼装是一次性的  
        }  
        #endregion  
    }

}

public static class ExpressionGenericMapperExtend  
{  
    public static string GetMappingName(this PropertyInfo prop)  
    {

        if (prop.IsDefined(typeof(MappingAttribute), true))  
        {  
            MappingAttribute display = prop.GetCustomAttribute(typeof(MappingAttribute)) as MappingAttribute;  
            return display.MappingName;  
        }  
        return prop.Name;

    }

    public static string GetMappingName(this FieldInfo prop)  
    {

        if (prop.IsDefined(typeof(MappingAttribute), true))  
        {  
            MappingAttribute display = prop.GetCustomAttribute(typeof(MappingAttribute)) as MappingAttribute;  
            return display.MappingName;  
        }  
        return prop.Name;

    }  
}

\[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)\]  
public class MappingAttribute : Attribute  
{  
    public string MappingName;  
    public MappingAttribute(string \_MappingName)  
    {  
        this.MappingName = \_MappingName;  
    }

}