我过分简化了这一点,因为我正在寻找一个通用的答案。假设我有一个像这样的表格设置:
Parent
recno int (unique, pk)
date datetime
stuff varchar(50)
Child
parentrecno (int, fk) --- PK
sequence (int) --- PK
data varchar(50)
在我的C#程序中,我经历了很多麻烦,找到了我感兴趣的父记录并将它们填入列表中。 Parent是一个非常大的表,我宁愿不查询它。所以我松开了钥匙:
List<int> recs = (from d in Parent where [.....] select d.recno).ToList();
稍后在Linq我可以说,找到相关父母的所有子记录:
var kids = from k in database.Childs
where recs.Contains(k.parentrecno)
select new { k };
在recs包含超过2100个条目之前,这一切都很棒。然后我收到TDS RPC错误(参数太多)。
我能看到它的方式:
直接用SQL做整件事(真的不想用DataReader来解决麻烦等等)。有一个外部系统涉及对记录进行鉴定,所以我不知道这是否完全可能。另外,我会生成两次列表 - 一次我需要在.Contains()中使用它,再次用于其他目的。
打破列表(recs),然后以块的形式阅读Child。
如果我把它分成几块,那么我漂亮的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);
因为List recs将包含需要组合在一起的内容,但必须为Linq查询拆分。
答案 0 :(得分:2)
我们使用SQL函数将varchar(max)分隔的值列表作为参数并返回表变量。 linq看起来像这样:
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
答案 1 :(得分:0)
您可以编写两个存储过程并通过LINQ使用它们,而不是使用SQL和DataReader。或者甚至通过LINQ读取id列表并将其作为输入提供给存储过程。
您可能无法解决太多的参数问题(您是否有权访问数据库)并且块解决方案不是很好,并且由于第二个查询而无法解决整个问题。 / p>
编辑:由于recs
集合并非完全由数据库生成,因此您需要某种方法来告知数据库此集合的内容。我认为你最好的选择是使用一个存储过程(或两个)接受集合作为一个大的逗号分隔字符串。在存储过程中,您再次将字符串拆分为ID。
顺便说一句,如果您使用的是SQL Server 2008,那么有一种比字符串解析更好的方法:table-valued parameters。您可以将表作为参数传递给存储过程。
答案 2 :(得分:0)
这看起来像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);
输出:
2000
2500
您可以在字典创建代码中使用相同的Join,如下所示:
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);
答案 3 :(得分:0)
我认为这就是你要找的东西:
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();