• LINQ.Contains超过2100记录报异常Exception的问题


    今天遇到一个LINQ的异常: 传入的表格格式数据流(TDS)远程过程调用(RPC)协议流不正确。此 RPC 请求中提供了过多的参数。最多应为 2100。

    代码是:

    Table<MyEntity> tbl = dataContext.GetTable<MyEntity>();
    tbl.
    where(t => AnotherList.Contains(t.EntityID)).select(....)

    报错的地方就是.Contains函数,当AnotherList的元素个数超过2100,LINQ的.Contains最大支持2100,超过就会报这个异常。这句LINQ背后的SQL语句可能是这样的:

    SELECT [t0].....
    FROM MyEntity AS [t0]
    WHERE [t0].[EntityID] IN (@p0, @p1, @p2, @p3, @p4......2100)

    所以就遇到SQL过长的问题,微软为了防止这个问题,就人为LINQ.Contains()限制了2100这个数量,很是奇怪。

    解决办法很简单,只要将调用数据源的AsEnumerable()运算符就可以了。例如:

    var tbl = dataContext.GetTable<MyEntity>().AsEnumerable();
    tbl.
    where(t => AnotherList.Contains(t.EntityID)).select(....)

    其它方法也有,就是转变思路,用JOIN的方式,而不要用WHERE ... IN (...,...,...)的方式。


    为什么.AsEnumerable()这么神奇?


    从MSDN看到,调用这个方法会返回一个 IEnumerable<T> 对象,而大家知道,和IQueryable比较起来,IEnumerable<T>是用了LINQ2Object的方式,而不是LINQ2SQL的方式,前者数据是在内存中处理的,而后者是在server上运行的。换句话说,本地数据源用IEnumerable<T>,数据在内存中,并且查询的逻辑可以直接用你所定义的方法的逻辑(因为有上下文);远程数据源用IQueryable<T>,无法直接使用你所定义的方法的逻辑,必须先生成表达式树,查询由源对象处理;IQueryable<T>类型可以在最终的执行前加一些方法,然后再返回最终的IQueryable<T>;而IEnumerable<T>已经包含了你执行查询后的所有结果,这时你的添加方法都是在已经有的结果集里进行。一言以蔽之,上面的2100的问题解决方法就是避免了LINQ2SQL生成表达式树查询远程服务器!

    这个方法有个副作用:调用dataContext.GetTable<MyEntity>().AsEnumerable()的副作用是吃内存,如果这个table很大,估计内存空间会消耗很大。

    此外,调用AsEnumerable()会导致Enumerable.Where运行,而不是原生的.Where运行,看个例子:

    1 public class ProductList : List<Product>
    2 {
    3 public IEnumerable<Product> Where(Func<Product, bool> predicate)
    4 {
    5 Console.WriteLine("Got Here");
    6 foreach (var product in this)
    7 {
    8 if (predicate(product))
    9 {
    10 yield return product;
    11 }
    12 }
    13 }
    14 }
    15
    16
    17 var products = productList
    18 .Where(p => p.Name.Contains(productName))
    19 .ToArray();
    20
    21  //Console输出 “Got Here”
    22  
    23 var products = productList
    24 .AsEnumerable()
    25 .Where(p => p.Name.Contains(productName))
    26 .ToArray();
    27  //Console没有输出
  • 相关阅读:
    static的全部用法收集整理
    文思创新复试及一些自己的思考
    “一碗牛肉面”引发的管理难题
    信必优面试实录
    我做PM(项目经理)这段时间...
    什么是面向对象?
    沟通
    体会Bind和Eval的不同用法
    北京艾德思奇科技有限公司面试实录
    今天去sony公司面试实录
  • 原文地址:https://www.cnblogs.com/Mainz/p/1971113.html
Copyright © 2020-2023  润新知