web-dev-qa-db-ja.com

Contains()を使用するときに2100パラメーター制限に達する(SQL Server)

_from f in CUSTOMERS
where depts.Contains(f.DEPT_ID)
select f.NAME
_

deptsは部門IDのリスト(_IEnumerable<int>_)です

このクエリは、大きなリスト(たとえば、約3000の部門ID)を渡すまで正常に機能します。その後、このエラーが発生します。

着信の表形式データストリーム(TDS)リモートプロシージャコール(RPC)プロトコルストリームが正しくありません。このRPC要求で指定されたパラメーターが多すぎます。最大は2100です。

クエリを次のように変更しました。

_var dept_ids = string.Join(" ", depts.ToStringArray());
from f in CUSTOMERS
where dept_ids.IndexOf(Convert.ToString(f.DEPT_id)) != -1
select f.NAME
_

IndexOf()を使用するとエラーが修正されましたが、クエリが遅くなりました。これを解決する他の方法はありますか?本当にありがとう。

57
ban-G

私の解決策(ガイド->ガイドのリスト):

List<tstTest> tsts = new List<tstTest>();
for(int i = 0; i < Math.Ceiling((double)Guides.Count / 2000); i++)
{
    tsts.AddRange(dc.tstTests.Where(x => Guides.Skip(i * 2000).Take(2000).Contains(x.tstGuid)));
}
this.DataContext = tsts;
12
ADM-IT

クエリをSQLで記述して、エンティティを添付してみませんか?

Linqで働いてからしばらく経ちましたが、次のようになります。

IQuery q = Session.CreateQuery(@"
         select * 
         from customerTable f
         where f.DEPT_id in (" + string.Join(",", depts.ToStringArray()) + ")");
q.AttachEntity(CUSTOMER);

もちろん、注射から保護する必要がありますが、それは難しくありません。

7
Joel

LINQKitプロジェクト をチェックアウトすることをお勧めします。この問題を解決するために、そのようなステートメントをバッチ処理する手法がどこかにあるからです。 PredicateBuilderを使用してローカルコレクションをより小さなチャンクに分割することがアイデアだと思いますが、これを処理するより自然な方法を探しているため、ソリューションを詳細に検討していません。

残念ながら、 Microsoftの私の提案に対する応答 から、.NET Framework 4.0または後続のサービスに対処する計画はないというこの動作を修正するようですパック。

https://connect.Microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=475984

更新:

これが LINQ to SQL または ADOで修正されるかどうかに関する議論を開きました。 MSDNフォーラムのNET Entity Framework 。これらのトピックに関する詳細と、XMLとSQL UDFを使用して思いついた一時的な回避策については、これらの投稿を参照してください。

1
jpierson

Linqによって生成されたINステートメントにパラメーターとして渡す前に、常にdeptsのリストを小さなセットに分割できます。こちらをご覧ください:

大規模なIEnumerableを固定量の項目の小さなIEnumerableに分割する

0
Stephen Burns

私は同様の問題を抱えていたので、それを修正する2つの方法がありました。

  1. 交差 メソッド
  2. iDで参加する

リストにない値を取得するには、 Except method OR left join。

更新

EntityFramework 6.2は、次のクエリを正常に実行します。

var employeeIDs = Enumerable.Range(3, 5000);
var orders =
    from order in Orders
    where employeeIDs.Contains((int)order.EmployeeID)
    select order;
0
Roman O