【问题标题】:Convert Complex Expression<Func<TDTO>,bool> to Expression<Func<TEntity>,bool>将复杂表达式<Func<TDTO>,bool> 转换为 Expression<Func<TEntity>,bool>
【发布时间】:2012-07-01 17:05:59
【问题描述】:

我的框架中有 DTOmodel。 BLL 和 View 根本看不到 EntiyModel。我想在图层之间传输和转换复杂表达式。

这是BLL中的一个方法……

//// BLL(Service)
Public PersonDTO getAll(Expression<Func<PersonDTO, bool>> whereCondition)
{

   return _repository.getAll(whereCondition);

}


// DLL(Repository)

Public PersonDTO getAll(Expression<Func<PersonDTO, bool>> whereCondition)
{

   Expression<Func<Person, bool>> NewCondition = ?/ How Convert DTOwhereCondition ???

   return DataContext.Persons(NewCondition);

}

///// 我想像这样在 PersonDTO 上创建复杂的表达式:

var persons = serive.getPersons(i => i.PersonDetailsDTO.Count == 3);

///// 我的课程

     public class Person
       {
        public Int32 Id { get; set; }
        public String FirstName { get; set; }
        public String LastName { get; set; }
        public List<PersonDetail> PersonDetails { get; set; }
       }


    public class PersonDTO
      {
        public Int32 Id { get; set; }
        public String FirstName { get; set; }
        public String LastName { get; set; }
        public List<PersonDetailDTO> PersonDetailsDTO { get; set; }
      }

【问题讨论】:

  • 不太清楚您要做什么。您可能想提供更多信息。如果你有表达式作为参数,你可以传递一个 lambda 表达式。

标签: c# architecture expression n-tier-architecture


【解决方案1】:

我使用 AutoMapper 将使用 DTO 的表达式转换为实体。表达式映射是 AutoMapper.Extensions.ExpressionMapping 包的一部分。当您调用 AddAutoMapper(它本身是 IServiceCollection 的扩展方法)时,您实际上必须调用 AddExpressionMapping

【讨论】:

    【解决方案2】:

    这是最基本的解决方案。如果您需要更多功能,也许您可​​以从那里开始工作。到目前为止,它允许选择性地提供一个委托来解析映射的属性名称,但属性类型必须相同。

    用法:

    var mappedExpression =
        ExpressionMapper<Person>.MapFrom(originalDtoExpression, null);
    
    // or:
    
    var mappedExpression =
        ExpressionMapper<Person>.MapFrom(originalDtoExpression,
                entityPropertyName => someMapper.ResolveDtoPropertyName(entityPropertyName));
    

    实施:

    public class ExpressionMapper<TTarget> : ExpressionVisitor
    {
        protected ExpressionMapper(Type sourceType, Func<string, string> resolveTargetMemberNameFunc)
        {
            this.SourceType = sourceType;
            this.ResolveTargetMemberNameFunc = resolveTargetMemberNameFunc ?? (cur => cur);
        }
    
        public Func<string, string> ResolveTargetMemberNameFunc { get; private set; }
    
        public Type SourceType { get; private set; }
    
        public static Expression MapFrom<TSource>(Expression sourceExpression, Func<string, string> resolveTargetMemberNameFunc)
        {
            return new ExpressionMapper<TTarget>(typeof(TSource), resolveTargetMemberNameFunc).Visit(sourceExpression);
        }
    
        public static Expression<Func<TTarget, bool>> MapFrom<TSource>(Expression<Func<TSource, bool>> sourcePredicateExpression, Func<string, string> resolveTargetMemberNameFunc)
        {
            return Expression.Lambda<Func<TTarget, bool>>(
                    MapFrom<TSource>(sourcePredicateExpression.Body, resolveTargetMemberNameFunc),
                    Expression.Parameter(typeof(TTarget), sourcePredicateExpression.Parameters[0].Name));
        }
    
        protected override Expression VisitMember(MemberExpression node)
        {
            var sourceMemberName = node.Member.Name;
            var targetNode = this.Visit(node.Expression);
            var targetMemberName = this.ResolveTargetMemberNameFunc(sourceMemberName);
            var targetMember = targetNode.Type.GetMember(targetMemberName).FirstOrDefault();
    
            if (targetMember == null)
            {
                throw new NotSupportedException(String.Format("The source type '{0}' cannot be mapped to the target type '{1}', because that target type has no member '{2}'.", node.Expression.Type.Name, targetNode.Type.Name, targetMemberName));
            }
    
            return Expression.MakeMemberAccess(targetNode, targetMember);
        }
    
        protected override Expression VisitParameter(ParameterExpression node)
        {
            if (node.Type == this.SourceType)
            {
                return Expression.Parameter(typeof(TTarget), node.Name);
            }
    
            return node;
        }
    }
    

    【讨论】:

    • 感谢您的回答。你测试过这段代码吗? 1- 它返回复杂查询的错误,如下所示: var people = serive.getPersons(i => i.PersonDetailsDTO.Count == 3); 2- 它不适用于像这样的简单查询: var people = serive.getPersons(i => i.firstName == "name");当我执行 WhereCondition 并想要访问 Persons.Count() 时,我检索到此异常:{"参数 'i' 未绑定在指定的 LINQ to Entities 查询表达式中。"} System.SystemException {System. InvalidOperationException}。 谢谢。
    • 正如我所说,这是您可以用作起点的最简单的方法。一般来说,这是非常困难和复杂的,可能不可能添加任何可能的用例。如果您需要实现缺少的内容,则必须了解有关表达式树的更多信息。 1) 绝对不支持嵌套 DTO。 2)这就是我一直成功使用它的方式,但没有.Count()。暂时不能说这里有什么问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-25
    • 1970-01-01
    相关资源
    最近更新 更多