Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
大集合的Linq.Contains导致TDS错误_Linq_Tsql - Fatal编程技术网

大集合的Linq.Contains导致TDS错误

大集合的Linq.Contains导致TDS错误,linq,tsql,Linq,Tsql,我把它简化了一点,因为我在寻找一个通用的答案。假设我有一个这样的桌子: Parent recno int (unique, pk) date datetime stuff varchar(50) Child parentrecno (int, fk) --- PK sequence (int) --- PK data varchar(50) from a in Context.SomeTable join nl in Context.

我把它简化了一点,因为我在寻找一个通用的答案。假设我有一个这样的桌子:

Parent
recno    int (unique, pk)
date     datetime
stuff    varchar(50)

Child
parentrecno (int, fk)   --- PK
sequence    (int)       --- PK
data     varchar(50)
from a in Context.SomeTable    
join nl in Context.ParseDelimited(nodeIdList) on a.NodeId.ToString() equals nl.FieldValue
在我的C程序中,为了找到我感兴趣的父记录并将它们填入一个列表,我经历了很多麻烦。Parent是一个非常大的表,我不想查询它。所以我把钥匙藏起来:

List<int> recs = (from d in Parent where [.....] select d.recno).ToList();
在REC包含2100多个条目之前,这一切都很好。然后我得到一个TDS RPC错误,参数太多

在我看来,我可以:

用直接的SQL来完成所有事情其实并不想用DataReader来完成这些麻烦,等等。。。。鉴定记录涉及到一个外部系统,所以我也不知道这是否完全可能。另外,我将生成该列表两次—一次是在.Contains中需要使用它时,另一次是用于其他目的

将列表中的记录分开,然后分块读取子项

如果我把它分成几块,那么我的漂亮Linq再往下一点就不起作用了:

var kids2 = (from kid in paydb.Childs
         where
             recs.Contains(kid.parentrecno)
         group pay by kid.parentrecno into kgroup
         select new { ParentRecNo = kgroup.Key, KidRecords = kgroup })
              .ToDictionary(kx => kx.ParentRecNo);

因为列表记录将包含需要分组在一起的内容,但对于Linq查询,这些内容必须分开。

您也可以编写两个存储过程并通过Linq使用它们,而不是使用SQL和DataReader。甚至可以通过LINQ读取id列表,并将其作为存储过程的输入

您可能无法解决参数太多的问题—您是否有访问数据库的权限,区块解决方案不是很好,并且由于第二次查询而无法解决整个问题

编辑:由于recs集合不是完全由数据库生成的,因此需要某种方法来告诉数据库此集合的内容。我认为最好的选择是使用一两个存储过程,将集合作为逗号分隔的大字符串接受。在存储过程中,再次将字符串拆分为ID

这解释了如何编写和使用分割字符串函数


顺便说一下,如果您使用的是SQL Server 2008,有一种比字符串解析更好的方法:。可以将表作为参数传递给存储过程。

这看起来像是Linq.Join的作业。我在下面使用了对象而不是数据库作为数据源,但如果您的LinqToSql提供程序支持,则其概念是相同的

List<int> recs = new List<int>(Enumerable.Range(1, 2500));
List<Child> children = new List<Child>(Enumerable.Range(2000, 1000)
    .Select(x => new Child
    {
        ParentRecNo = x
    }));

var kids = children.Join(recs, x => x.ParentRecNo, y => y, (x, y) => x);

Console.WriteLine(kids.First().ParentRecNo);
Console.WriteLine(kids.Last().ParentRecNo);
您可以在字典创建代码中使用相同的联接,如下所示:

var kids2 = children
    .Join(recs, x => x.ParentRecNo, y => y, (x, y) => x)
    .GroupBy(x => x.ParentRecNo)
    .Select(kgroup => new
        {
            ParentRecNo = kgroup.Key,
            KidRecords = kgroup
        })
    .ToDictionary(kx => kx.ParentRecNo);

我想这就是你想要的:

List<Child> children = 
database.Parents.Where( 'your favourite lambda expression').Select(x=>x.Childs).ToList();
所以。。。我不知道您使用什么条件来获取父对象,但希望可以使用lambda表达式来实现,例如:

List<Child> children = database.Parents
     .Where(p=>p.recno > 10 && p.recno < 40)
     .Select(x=>x.Childs).ToList();

我们使用一个SQL函数,将varcharmax分隔的值列表作为参数,并返回一个表变量。linq如下所示:

Parent
recno    int (unique, pk)
date     datetime
stuff    varchar(50)

Child
parentrecno (int, fk)   --- PK
sequence    (int)       --- PK
data     varchar(50)
from a in Context.SomeTable    
join nl in Context.ParseDelimited(nodeIdList) on a.NodeId.ToString() equals nl.FieldValue
其中nodeIdList是一个字符串变量,包含来自上一个查询的ID列表。丑陋,但它确实绕过了2100参数限制

create function dbo.ParseDelimited(@delimitedList NVARCHAR(MAX)) returns @tblSample table(counter int, fieldValue NVARCHAR(100)) 
WITH SCHEMABINDING
as
begin
  declare @counter    NVARCHAR(  4)
  declare @fieldValue NVARCHAR(100)

  declare @tmpTable table(counter int primary key, fieldValue NVARCHAR(100))

  set @counter = 1

  while charindex(',', @delimitedList) > 0
  begin
    set @fieldValue = ltrim(rtrim(substring(@delimitedList, 1, charIndex(',', @delimitedList)-1)))

    insert into @tmpTable select @counter, @fieldValue

    set @delimitedList = ltrim(rtrim(substring(@delimitedList, (charindex(',', @delimitedList) + 1), len(@delimitedList))))

    set @counter = @counter + 1
  end

  if ltrim(rtrim(@delimitedList)) != ''
  begin
    insert into @tmpTable select @counter, @delimitedList
  end

  insert into @tblSample select counter, fieldValue from @tmpTable

  return
end

我最大的问题是,确认REC中的记录并不是全部用SQL完成的——这涉及到另一个系统。能够将这些键放入一个临时表中也会起作用,但我认为我也无法从Linq访问该临时表。我更新了我的答案,并提供了一些关于如何解决问题的附加信息。很好的解决方案。我唯一担心的是数据库中可能记录的数量非常大。数据是先被检索,然后被合并——在检索后删除不需要的记录,还是在SQL Server端被删除,然后结果被删除?这不起作用。您试图在SQL查询中使用客户端IEnumerable REC,该查询仅支持Contains,它将被转换为in表达式。问问自己LINQtoSQL应该如何通知数据库REC的内容。唯一可行的方法是,首先将整个Childs表的内容发送到客户端,然后使用REC进行连接。仅获取ChildId和ParentRecordId在客户端进行连接可能成本较低。接下来是查询匹配记录的子详细信息,和/或将其分解为小于2100的块,可能使用insettsof实现。最后,SQL Server 2008(如果是选项Clint)似乎增加了表值参数,以绕过2100参数限制。John,请提供一些解决方案示例。