• Lamda Expression


    Expression<Func<Student, bool>> filter=s=>s.Name.Contains("a") && s.Age>=20;

    这样的表达试转换成

    Expression<Func<DataRow, bool>> filter = r=>((string)r["Name"]).Contains("a") && ((int)r["Age"])>=20;

    也许你会问,干嘛要这样做呢?举个例子,

    说DAL里有一个类StudentProvider用于对student进行数据库的增删改查的操作。我们就拿查询来说,查询可以有很多的条件。以往可能会有类似的方法:

    public IEnumerable<Student> GetStudentsByName(string name);
    public Student GetStudentById(int id);

    但是别忘了今天的世界有了Expression,我们应该向这些落后的(别打我,窃以为的)方法说再见了。高颜值的接口当然要写成这样了:

    public IEnumerable<Student> GetStudents(Expression<Func<Student, bool>> filter);

    于是我们来看看这个方法的实现,

    复制代码
         public IEnumerable<Student> GetStudents(Expression<Func<Student, bool>> filter)
            {
                using (var connection=new SqlConnection("some connection string"))
                {
                    var selectSql = "SELECT * FROM Student";
                    using (var adapter = new SqlDataAdapter(selectSql, connection))
                    {
                        var ds = new DataSet();
                        adapter.Fill(ds, "table");
                        return from raw in ds.Tables["table"].AsEnumerable() select new Student(raw);
                    }
                }
            } 
    复制代码

    实现用到了Linq to DataSet, 其实我们真正想做的是

    return from raw in ds.Tables["table"].AsEnumerable().Where(filter) select new Student(raw)

    但是问题是Where只接受

    Func<DataRow, bool> predicate

    到这里,终于明白了为什么要做LambdaExpression变换了吧。

    前一篇中我们看到了ExpressionVisitor的强大,这里我们还要用他来解决问题。我们引入一个ConvertMemberToColumnVisitor:

    复制代码
         public class ConvertMemberToColumnVisitor : ExpressionVisitor
            {
                private readonly Expression _columnOwnerExpression;
                private readonly string _memberOwnerName;
    
                public ConvertMemberToColumnVisitor(Expression columnOwnerExpression, string memberOwnerName)
                {
                    _columnOwnerExpression = columnOwnerExpression;
                    _memberOwnerName = memberOwnerName;
                }
    
                protected override Expression VisitMember(MemberExpression node)
                {
                    var parameterExpression = node.Expression as ParameterExpression;
                    if (parameterExpression != null && parameterExpression.Name == _memberOwnerName)
                    {
                        return Expression.Convert(Expression.Call(_columnOwnerExpression, typeof(DataRow).GetMethod("get_Item", new []{typeof(string)}), Expression.Constant(node.Member.Name)),
                            ((PropertyInfo)node.Member).PropertyType);
                    }
    
                    return base.VisitMember(node);
                }
            }
    复制代码

    很简单,很定一个我们要替代成的表达式,当然我们还是用parameter name来匹配所以要给定一个参数名。

    有了这个Visitor后,一切问题都简单了:

    复制代码
         public IEnumerable<Student> GetStudents(Expression<Func<Student, bool>> filter)
            {
                using (var connection=new SqlConnection("some connection string"))
                {
                    var selectSql = "SELECT * FROM Student";
                    using (var adapter = new SqlDataAdapter(selectSql, connection))
                    {
                        var ds = new DataSet();
                        adapter.Fill(ds, "table");
    
                        var p1 = Expression.Parameter(typeof(DataRow), "r");
                        var converter = new ConvertMemberToColumnVisitor(p1, filter.Parameters[0].Name);
                        var newExp = converter.Visit(filter);
                        var lambda = Expression.Lambda<Func<DataRow, bool>>(((LambdaExpression)newExp).Body, p1);
                        var predicate = lambda.Compile();
                        return from raw in ds.Tables["table"].AsEnumerable().Where(predicate) select new Student(raw);
                    }
                }
            } 
    复制代码
  • 相关阅读:
    Element-ui前端自定义排序
    elementUI --- el-select 下拉框样式覆盖
    Oracle中,利用sql语句中的函数实现保留两位小数和四舍五入保留两位小数
    ORA-01476: divisor is equal to zero解决方法
    Linux下安装Mysql
    Fastdfs安装
    java基础
    Markdown学习
    Maven构建SpringMVC环境报错“java.lang.ClassNotFoundException: org.springframework.web.servlet. DispatcherSe
    解决IDEA提示Untrusted Server's certificate 证书不可用( Server's certificate is not trusted )
  • 原文地址:https://www.cnblogs.com/wang-jee/p/10781650.html
Copyright © 2020-2023  润新知