传入请求参数过多。服务器最多支持2100个参数

问题描述 投票:0回答:8

我有一个看似简单的 linq-to-sql 查询,它可以搜索多个列中的某些数据;像这样的:

List<long> TheTableIDs = list of IDs (sometimes more than 2100)

var QueryOutput = (from x in TheDataContext.SomeTable

                   where TheTableIDs.Contains(x.ID) &&
                   
                   x.Col1.Contains(SomeString) || 
                   x.Col2.Contains(SomeString))

                   select x.ID).ToList();

我得到的错误是这样的:

附加信息:传入请求参数过多。 服务器最多支持2100个参数。减少数量 参数并重新发送请求。

解决这个问题的最佳方法是什么?

我环顾四周,找到了一个解决方案,如下所示:

var QueryOutput = TheDataContext.SomeTable.AsEnumerable()

        .Join(TheTableIDs, x => x.LeadID, ci => ci, (x, ci) => x)

        .Where(x => SomeString.Contains(x.Col1) == true ||
                    SomeString.Contains(x.Col2) == true)
        
        .Select(x => x.ID).ToList();

此编译不会引发任何异常,但似乎忽略了带有

Where
SomeString.Contains

子句

使该查询有效的解决方案是什么?

c# linq
8个回答
31
投票

简单 - 只要 TheTAbleID 包含的 ID 少于 2100 个 - 这样做是不合法的。

将表切成 2000 个块,然后单独查询每个块,可能在多个线程中。


15
投票

SQL 不支持在

in
语句中使用超过 2100 个值,但您可以在具有超过 2100 行的表中使用,这样您就可以将数据插入表中并更改查询以通过选择来检查
in
那张桌子

例如

Create TempIDs (bigint ID, uniqueidentifier guid)

guid 列用于防止混合不同的用户数据

在你的代码中

Guid myKey = Guid.New();
List<long> TheTableIDs = list of IDs (sometimes more than 2100)
TheDataContext.TempIDs.InsertAllOnSubmit(TheTableIDs.select(i => new TempIDs{ID = i, Guid = mykey});
TheDataContext.SubmitChanges();

var QueryOutput = (from x in TheDataContext.SomeTable

                   where TheDataContext.TempIDs.Contains(x.ID) &&

                   x.Col1.Contains(SomeString) || 
                   x.Col2.Contains(SomeString))

                   select x.ID).ToList();

如果您可以从数据库中检索 ids,您可以在 sql 中编写一个表值函数来返回 ids 并在代码中对该函数进行建模,假设它的名称是

fnGetIds
。 然后在您的代码中使用它,如下所示

var QueryOutput = (from x in TheDataContext.SomeTable

                   where TheDataContext.fnGetIds().Contains(x.ID) &&

                   x.Col1.Contains(SomeString) || 
                   x.Col2.Contains(SomeString))

                   select x.ID).ToList();

2
投票

使用 2 个 where 子句:

List<long> TheTableIDs = list of IDs (sometimes more than 2100)

var _QueryOutput = (from x in TheDataContext.SomeTable
    where x.Col1.Contains(SomeString) || x.Col2.Contains(SomeString))
    select x.ID).ToList();

var QueryOutput = _QueryOutput.Where(w => TheTableIDs.Contains(w)).ToList();

为了提高效率,您可以重构代码,以便仅在列表包含超过 2000 个时才这样做:

if (TheTableIDs.Count() > 2000)
   // Code Here
else
   // Code Here

1
投票

我得到了这个,我无法使用 2100 个参数!还有其他事情正在发生。

经过仔细检查,我发现我在循环中添加了 5 个参数,但源对象没有被清除,因此要插入的对象列表变得越来越大。

 Dim reportNum = 1

                For Each report In wwo.wwoWeatherReport.listOfForecasts
                    'whack these into the  regionsAndCountries
                    db.addParameter("@forecastAirTemp" & reportNum, report.listOfhourlyForecasts(0).hourlyForecast_tempC)
                    db.addParameter("@forecastRainFall" & reportNum, report.listOfhourlyForecasts(0).hourlyForecast_precipMM)
                    reportNum = reportNum + 1

                Next

我必须事先调暗一个新的 wwo 对象并对其进行排序

Dim wwo As New wwwoManager

Dim reportNum = 1  ...

0
投票

这里的问题是使用 Contains ,它需要在单独的查询中:

List<long> TheTableIDs = list of IDs (sometimes more than 2100)

var QueryOutput = (from x in TheDataContext.SomeTable

                   where TheTableIDs.Contains(x.ID) 

                   select x.ID).ToList();

foreach(var s in QueryOutput){
   if(x.Col1.Contains(SomeString) || x.Col2.Contains(SomeString)){
      //do something
   }
}

0
投票

我的解决方案是使用用户定义表来传入一组数据作为参数。

实体框架核心相当简单:

 public IQueryable<Item> GetItemsByIds(IEnumerable<long> itemIds)
    {
                var items = this.DbContext.Items.FromSql(
                            GetCommand(),
                            GetParameters(itemIds));
    
                return items;
    }


 public static string GetCommand()
                    {
                        return $"EXEC CommandName @ItemIds";
                    }



 public static SqlParameter[] GetParameters(IEnumerable<long> itemIds)
                    {
                        var ids = new DataTable();
                        ids.Columns.Add("Id", typeof(long));
    
                        foreach (var itemId in itemIds)
                        {
                            ids.Rows.Add(itemId);
                        }
    
                        var itemIdsParam = new SqlParameter("@ItemIds", SqlDbType.Structured)
                        {
                            Value = ids,
                            TypeName = "[ItemDbo].[udtID]"
                        };

                    var paramList = new List<SqlParameter>
                    {
                        itemIdsParam 
                    };

                    return paramList.ToArray();
                }

当然,您必须首先在sql server中创建UDT和存储过程。


0
投票

如果将

TheTableIDs
更改为
IQueryable<long>
类型,问题就可以解决。

您应该修改生成

TheTableIDs
的查询。

例如使用以下代码:

var TheTableIDs = db.SomeTable.Select(d => d.ID);

而不是:

var TheTableIDs = db.SomeTable.Select(d => d.ID).AsEnumerable();

-1
投票

更改了此查询:

var z = (from b in db.GradeChangeHistories
    where m_list.Contains(b.SessionKey) 
    select b);

为此,它有效:

var z = (from b in db.GradeChangeHistories        
    select b).ToList().Where(x => m_list.Contains(x.SessionKey));
© www.soinside.com 2019 - 2024. All rights reserved.