ড্যাপার ওআরএম সহ এক্স (যেখানে) আইডি থেকে * নির্বাচন করুন


231

আইএন ক্লজের মানগুলির তালিকা যখন ব্যবসায় যুক্তি থেকে আসছে তখন ড্যাপার ওআরএম ব্যবহার করে আইএন ক্লজ দিয়ে কোন ক্যোয়ারী লেখার সর্বোত্তম উপায় কী? উদাহরণস্বরূপ বলা যাক যে আমার কাছে একটি প্রশ্ন রয়েছে:

SELECT * 
  FROM SomeTable 
 WHERE id IN (commaSeparatedListOfIDs)

commaSeparatedListOfIDsব্যবসা লজিক থেকে পাস হচ্ছে এবং এটি কোন প্রকার হতে পারে IEnumerable(of Integer)। এই ক্ষেত্রে আমি কীভাবে কোনও প্রশ্ন তৈরি করব? আমি এখন পর্যন্ত যা করছি তা করতে হবে যা মূলত স্ট্রিং কনটেনটেশন বা এমন কোনও প্রকারের পরামিতি ম্যাপিং কৌশল রয়েছে যা সম্পর্কে আমি অবগত নই?

উত্তর:


365

ড্যাপার সরাসরি এটি সমর্থন করে। উদাহরণ স্বরূপ...

string sql = "SELECT * FROM SomeTable WHERE id IN @ids"
var results = conn.Query(sql, new { ids = new[] { 1, 2, 3, 4, 5 }});

46
আমি মনে করি এটি নোট করা জরুরী যে আপনি কতগুলি আইটেম আপনার অ্যারে প্রেরণ করতে পারবেন তার সীমাবদ্ধতা রয়েছে। যখন আমি অনেকগুলি আইডিতে পাস করি তখন আমি এই কঠিন উপায়টি উপলব্ধি করেছিলাম। আমি সঠিক সংখ্যাটি মনে রাখছি না তবে আমার স্মৃতি থেকে আমি মনে করি যে ড্যাপার ক্যোয়ারি কাজ করা / সম্পাদন বন্ধ করার আগে এটি 200 টি উপাদান।
মার্কো

7
মার্কো, এটি গুরুত্বপূর্ণ। এবং, আপনি যদি সেভাবে এটি করে থাকেন তবে আপনি আপনার ডেটা অনুসন্ধানের অন্য কোনও উপায় সন্ধানের কথা বিবেচনা করতে পারেন যেমন আইডির তালিকা পাস করার পরিবর্তে জয়েন বা অ্যান্টি-জয়েন করা। আইএন ক্লজটি সর্বাধিক সম্পাদনকারী কোয়েরি নয় এবং প্রায়শই একটি বিদ্যমান ধারা দ্বারা প্রতিস্থাপন করা যেতে পারে, এটি দ্রুত হবে।
ডন রোলিং

24
এফওয়াইআই - এসকিউএল সার্ভার ২০০৮ আর 2 এর ধারাটিতে 2100 এন্ট্রি সীমাবদ্ধ রয়েছে IN
জেসি

6
এবং এসকিউএলাইটের 999 ভেরিয়েবলের ডিফল্ট সীমা রয়েছে।
ক্যামেরন

8
সাবধানতা: এসকিউএল সার্ভারে এটি ব্যর্থ হয় যদি আপনার অ্যারেতে একাধিক আইটেম থাকে এবং আপনি বন্ধনীগুলিতে প্যারামিটারটি মুড়ে রাখেন। বন্ধনী অপসারণ করা সমস্যার সমাধান করবে।
আজবাইভেন

66

সরাসরি গিটহাব প্রকল্পের হোমপেজ থেকে :

ড্যাপার আপনাকে আইউনামেবলে পাস করার অনুমতি দেয় এবং স্বয়ংক্রিয়ভাবে আপনার ক্যোয়ারিকে প্যারামিটারাইজ করবে।

connection.Query<int>(
    @"select * 
      from (select 1 as Id union all select 2 union all select 3) as X 
      where Id in @Ids", 
    new { Ids = new int[] { 1, 2, 3 });

অনুবাদ করা হবে:

select * 
from (select 1 as Id union all select 2 union all select 3) as X 
where Id in (@Ids1, @Ids2, @Ids3)

// @Ids1 = 1 , @Ids2 = 2 , @Ids2 = 3

43

যদি আপনার INক্লাসটি এমএসএসকিউএল হ্যান্ডল করার জন্য খুব বড় হয় তবে আপনি খুব সহজেই ড্যাপারের সাহায্যে একটি টেবিলভ্যালিউপ্যারামিটার ব্যবহার করতে পারেন।

  1. এমএসএসকিউএলে আপনার টিভিপি টাইপ তৈরি করুন:

    CREATE TYPE [dbo].[MyTVP] AS TABLE([ProviderId] [int] NOT NULL)
  2. DataTableটিভিপি হিসাবে একই কলাম (গুলি) দিয়ে একটি তৈরি করুন এবং মান সহ এটি তৈরি করুন

    var tvpTable = new DataTable();
    tvpTable.Columns.Add(new DataColumn("ProviderId", typeof(int)));
    // fill the data table however you wish
    
  3. INNER JOINটিভিপি টেবিলটিতে একটি করতে আপনার ড্যাপার ক্যোয়ারীটি সংশোধন করুন :

    var query = @"SELECT * FROM Providers P
        INNER JOIN @tvp t ON p.ProviderId = t.ProviderId";
    
  4. আপনার ড্যাপার কোয়েরি কলটিতে ডেটা টেবিলটি পাস করুন

    sqlConn.Query(query, new {tvp = tvpTable.AsTableValuedParameter("dbo.MyTVP")});

আপনি একাধিক কলামের একটি গণ আপডেট করতে চাইলে এটি চমত্কারভাবে কাজ করে - কেবল টিভিপি তৈরি করুন এবং টিভিপিতে UPDATEঅভ্যন্তরীণ যোগদানের মাধ্যমে একটি করুন।


দুর্দান্ত সমাধানটি তবে কাজ করে না et নেট কোর, এই প্রশ্নটি দেখুন: stackoverflow.com/questions/41132350/… । এছাড়াও এই পৃষ্ঠাটি দেখুন: github.com/StackExchange/Dapper/issues/603
পিসিদেব

3
এছাড়াও আপনি উপার্জন কথা বিবেচনা করতে পারেন ProviderIdউপর MyTVPহতে PRIMARY KEY CLUSTERED(মান আমরা কোন সদৃশ অন্তর্ভুক্ত ক্ষণস্থায়ী ছিল), কারণ যে এই মাত্র আমাদের জন্য একটি কার্য-সম্পাদনার সমস্যা সমাধান।
রিচার্ডিসিমো

@ রিচার্ডিসিমো আপনি কীভাবে এটি করতে চান তার একটি উদাহরণ দেখিয়ে দিতে পারেন? আমি সিনট্যাক্সটি সঠিক বলে মনে হচ্ছে না।
মাইক কোল


14

আইডিগুলির একটি তালিকা ব্যবহার করে ড্যাপারের সাথে প্রচুর সংখ্যক সারি সন্ধানের জন্য এখানে সম্ভবত দ্রুততম উপায়। আমি আপনাকে প্রতিশ্রুতি দিচ্ছি যে আপনি এটি ভাবতে প্রায় যে কোনও উপায়ের তুলনায় দ্রুত (কোনও উত্তরে প্রদত্ত একটি টিভিপি ব্যবহারের সম্ভাব্য ব্যতিক্রম সহ, এবং যা আমি পরীক্ষা করি নি, তবে আমি সন্দেহ করি যে আপনি এখনও জনবসতিপূর্ণ হতে পারেন বলে আমি ধীর হতে পারি) টিভিপি)। এটি সিন্প্যাক্স ব্যবহার করে ড্যাপারের চেয়ে দ্রুততর গ্রহIN এবং সারিতে সারি সত্তা ফ্রেমওয়ার্কের চেয়ে দ্রুত ব্রহ্মাণ্ডগুলি । এবং এটি তালিকা VALUESবা UNION ALL SELECTআইটেমগুলিতে পাস করার চেয়েও মহাদেশগুলি দ্রুত faster এটি সহজেই একটি বহু-কলাম কী ব্যবহার করতে বাড়ানো যেতে পারে, কেবলমাত্র DataTableটেম্প টেম্পল এবং সংযুক্তির শর্তে অতিরিক্ত কলাম যুক্ত করুন ।

public IReadOnlyCollection<Item> GetItemsByItemIds(IEnumerable<int> items) {
   var itemList = new HashSet(items);
   if (itemList.Count == 0) { return Enumerable.Empty<Item>().ToList().AsReadOnly(); }

   var itemDataTable = new DataTable();
   itemDataTable.Columns.Add("ItemId", typeof(int));
   itemList.ForEach(itemid => itemDataTable.Rows.Add(itemid));

   using (SqlConnection conn = GetConnection()) // however you get a connection
   using (var transaction = conn.BeginTransaction()) {
      conn.Execute(
         "CREATE TABLE #Items (ItemId int NOT NULL PRIMARY KEY CLUSTERED);",
         transaction: transaction
      );

      new SqlBulkCopy(conn, SqlBulkCopyOptions.Default, transaction) {
         DestinationTableName = "#Items",
         BulkCopyTimeout = 3600 // ridiculously large
      }
         .WriteToServer(itemDataTable);
      var result = conn
         .Query<Item>(@"
            SELECT i.ItemId, i.ItemName
            FROM #Items x INNER JOIN dbo.Items i ON x.ItemId = i.ItemId
            DROP TABLE #Items;",
            transaction: transaction,
            commandTimeout: 3600
         )
         .ToList()
         .AsReadOnly();
      transaction.Rollback(); // Or commit if you like
      return result;
   }
}

সাবধান থাকুন যে আপনাকে বাল্ক সন্নিবেশ সম্পর্কে কিছুটা শিখতে হবে। ফায়ারিং ট্রিগার (ডিফল্টটি হ'ল নয়), সীমাবদ্ধতাগুলির সম্মান করা, টেবিলটি লক করা, একত্রে সন্নিবেশ প্রবেশকরণের অনুমতি প্রদান ইত্যাদির বিষয়ে বিকল্প রয়েছে।


হ্যাঁ আমি আইডিগুলির সাথে একটি টেম্প টেবিল তৈরি করার এবং তারপরে সেই টেবিলে অভ্যন্তরীণ যোগদানের আপনার সাধারণ ধারণার সাথে একমত। আমরা এটি অভ্যন্তরীণভাবে সম্পন্ন করেছি এবং এটি কোয়েরি পারফরম্যান্সকে মারাত্মকভাবে উন্নত করেছে। আমি নিশ্চিত না যে আমি কোনও কিছুর জন্য ডেটাটেবল ক্লাসটি ব্যবহার করব তবে আপনার সমাধানটি সম্পূর্ণ বৈধ। এটি অনেক দ্রুততর উপায়।
মার্কো

DataTableবাল্ক সন্নিবেশ জন্য প্রয়োজন। আপনি কিভাবে আপনি টেম্প টেবিলে 50,000 মান সন্নিবেশ?
এরিক

1
1000 এর অংশে যদি আমি সীমাটি সঠিকভাবে মনে করি? যাই হোক আমি জানি না আপনি ডেটা টেবিল দিয়ে সীমাটি বাইপাস করতে পারবেন তাই আমি আজ নতুন কিছু শিখলাম ...
মার্কো

1
আপনি এটির পরিবর্তে কোনও সারণী মান প্যারামিটার ব্যবহার করতে পারলে কাজটি হাস্যকর পরিমাণ। ড্যাপার একটি টিভিপি হিসাবে একটি ডেটা টেবিল পরিষ্কারভাবে সমর্থন করে, যা আপনাকে একটি টেম্প টেবিল তৈরি এবং ধ্বংসের পাশাপাশি বাল্ককপির মাধ্যমে সেই টেম্প টেবিলটিকে জনবসতি করতে দেয়। আইএন ক্লজের জন্য প্যারামিটারের সংখ্যা অনেক বেশি এমন ক্ষেত্রে আমরা টিভিপি ভিত্তিক সমাধানটি নিয়মিত ব্যবহার করি।
মিঃ টি

3
এটি কোনও হাস্যকর পরিমাণের কাজ নয়, বিশেষত যদি কোনও সহায়ক শ্রেণি বা এক্সটেনশন পদ্ধতিতে কেউ এটিকে কিছুটা দূরে সরিয়ে দেয়।
এরিক

11

এছাড়াও আপনার ক্যোয়ারী স্ট্রিংয়ের চারপাশে আপনি প্রথম বন্ধনী আবদ্ধ না করে তা নিশ্চিত করুন:

SELECT Name from [USER] WHERE [UserId] in (@ids)

আমার এই বন্ধুত্বগুলি অপসারণের মাধ্যমে ঠিক করা ড্যাপার 1.50.2 ব্যবহার করে একটি এসকিউএল সিন্ট্যাক্স ত্রুটি হয়েছিল

SELECT Name from [USER] WHERE [UserId] in @ids

7

আমরা একটি নিয়মিত এসকিউএল হিসাবে যেমন ক্লউজটি যুক্ত করার প্রয়োজন হয় না() । কারণ ড্যাপার আমাদের জন্য এটি স্বয়ংক্রিয়ভাবে করে। এখানে syntax:

const string SQL = "SELECT IntegerColumn, StringColumn FROM SomeTable WHERE IntegerColumn IN @listOfIntegers";

var conditions = new { listOfIntegers };

var results = connection.Query(SQL, conditions);

6

পোস্টগ্রিজের উদাহরণ:

string sql = "SELECT * FROM SomeTable WHERE id = ANY(@ids)"
var results = conn.Query(sql, new { ids = new[] { 1, 2, 3, 4, 5 }});

3

আমার ক্ষেত্রে আমি এটি ব্যবহার করেছি:

var query = "select * from table where Id IN @Ids";
var result = conn.Query<MyEntity>(query, new { Ids = ids });

দ্বিতীয় লাইনে আমার পরিবর্তনশীল "আইডিএস" হ'ল স্ট্রিংগুলির একটি মূল সংখ্যা, এটিও তারা অনুমান করে পূর্ণসংখ্যা হতে পারে।


List<string>?
কুইকিনেট

2

আমার অভিজ্ঞতায়, এর সাথে মোকাবিলার সর্বাধিক বন্ধুত্বপূর্ণ উপায় হ'ল একটি ফাংশন যা কোনও স্ট্রিংকে মান সারণীতে রূপান্তর করে।

ওয়েবে অনেকগুলি স্প্লিটার ফাংশন উপলব্ধ রয়েছে, আপনার এসকিউএল এর স্বাদ যদি আপনি সহজেই খুঁজে পেতে পারেন।

আপনি তখন করতে পারেন ...

SELECT * FROM table WHERE id IN (SELECT id FROM split(@list_of_ids))

অথবা

SELECT * FROM table INNER JOIN (SELECT id FROM split(@list_of_ids)) AS list ON list.id = table.id

(অথবা সাদৃশ্যপূর্ণ)

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.