详细内容
List查询,过滤重复项与查询特定字段的方法
发布日期:2013-01-25     点击:6579     字体:[ ]

对List操作:

这里的集合均代表List<T>类型,例如List<T> details = List<T>;


判断重复:details.Select(item => item.ApplyPersonId).Distinct().ToList();
这样即可取不重复的ApplyPersonId


条件: allDataListNew.Where(item => item.LeaveTypeId == data.LeaveTypeId)
                        .Where(item => item.ApplyPersonId == data.ApplyPersonId)
                        .Where(item => item.LeaveEventDate == data.LeaveEventDate)
                        .Select(item => item.Hours).Sum();
这里的筛选也可以写在一起:allDataListNew.Where(item => item.LeaveTypeId == data.LeaveTypeId &&
item.ApplyPersonId == data.ApplyPersonId &&  item.LeaveEventDate == data.LeaveEventDate).Select(item => item.Hours).Sum();


汇总(重新查询List中某项):
                decimal minutes = (from a in list
                                   where a.ApplyPersonId == personId
                                   select new FlowerLeaveApplyFormDetailEntity()
                                   {
                                       Hours = a.Hours
                                   }).ToList().Sum(item => item.Hours);

 

再发一篇网络上搜来的文章:

------------------------------------------------------------------------------------

Lambda动态附加条件和排序语句 (可用于linq to sql)

一种常见的情况, 使用linq-to-sql 或者lambda(Entity framework)去数据库取条件的时候需要附加多个条件或者排序语句

以 Name="John" Age=23 为例

先明确一个概念 对于Lambda来说 以下两个表达式是等价的

  1.  list.Where(p=>p.Name=="John" && p.Age==23)

  2.  list.Where(p=>p.Name=="John" ).Where(p=>p.Age==23)

lambda表达式只是创建了一个方法的定义 实际上并没有执行

真正的执行一般等到ToList()方法(内部其实是IEnumerable<T>)被执行的时候才真正的去取数据

而且lambda表达式支持如上所示使用多个小表达式的串联操作

那么如果有多个条件只要一直增加Where表达式就ok了

 

第二个问题, 以上的代码都是写死的 我们如何通过一般web上提交的string类型的键值对来过滤信息呢?

  例如我们收到的数据往往是 "Name":"John","Age"="23"

总不能写以下代码吧:

 

代码
复制代码
var list = context;
if (forms.ContainsKey("Name"))
{
list.Where(p
=> p.Name == forms["Name"]);
}
if (forms.ContainsKey("Age"))
{
list.Where(p
=> p.Age == Convert.ToInt32(forms["Age"]));
}
var data
= list.ToList();
复制代码

这些代码不仅仅扩展性不好.....而且加一个条件你就要加一个代码快,工作量大又容易出Bug

 

理想的做法应该想下面一样(注意 用where条件过滤的时候条件经常复杂 例如Age=10 , Age>10 , Name.Startwith("张")  所以实际上过滤条件一般不用下面的做法

真正用下面的做法的往往都是OrderBy age desc,name asc 这样的排序条件)

foreach (var item in forms.Keys)
{
list.Where(build condition.....);//在这里动态附加所有的条件
}

 

那么如何根据已知的string类型的属性名称和值 来创建表达式呢?以下是动态创建表达式的代码,以排序为例

 

代码
复制代码
var property = typeof(TSource).GetProperty(item);
var parameter
= Expression.Parameter(typeof(TSource), "p");
var propertyAccess
= Expression.MakeMemberAccess(parameter, property);
var orderByExp
= Expression.Lambda(propertyAccess, parameter);


if (message.Sort[item] == PageSortDirection.Ascending)//判断是升序还是降序 如果是应用到搜索条件 那么就是 判断应该用= > < like 还是别的什么
{
MethodCallExpression resultExp
= Expression.Call(typeof(Queryable), "OrderBy", new Type[] { typeof(TSource), property.PropertyType }, list.Expression, Expression.Quote(orderByExp));
list
= list.Provider.CreateQuery<TSource>(resultExp);
}
else
{
MethodCallExpression resultExp
= Expression.Call(typeof(Queryable), "OrderByDescending", new Type[] { typeof(TSource), property.PropertyType }, list.Expression, Expression.Quote(orderByExp));
list
= list.Provider.CreateQuery<TSource>(resultExp);
}
复制代码

千万不要直接用list=list.OrderBy(p=>orderByExp) 而应该用Expression.Call来组合语句

虽然两者最终出来的结果是一样的, 不过前者会把数据load到本地以后再过滤, 因为entity framework没法把这种动态的表达式直接解析为sql.

真正的逻辑就是根据每一个条件和排序表达式 构建一个Where 或者Order的表达式 然后逐个附加到现在的lambda表达式上

 

性能问题:

  考虑到Entity framework的应用场景, 还有权重问题(实际上数据库操作比这边的动态表达式耗性能多了)  这样的性能损耗是非常理想的

 

异常:

  如果传入的string实际上不是类型的属性,例如传了一个LastName 而class实际上没有这个属性 , 会抛出异常。

用户评论
昵称 
内容  *
验证码   
   
相关文章 更多...  
Copyright © 2010 zdbase.com All Rights Reserved. 苏ICP备15039389号 可人软件设计