.ToList (), .AsEumeume (), AsQueryable () এর মধ্যে পার্থক্য কী?


182

আমি লিনকিউ থেকে সত্তা এবং লিংকউ-এর কয়েকটি পার্থক্য জানি যা প্রথম প্রয়োগকারী IQueryableএবং দ্বিতীয় প্রয়োগ IEnumerableএবং আমার প্রশ্নের ক্ষেত্রটি EF 5 এর মধ্যে রয়েছে।

আমার প্রশ্ন হল এই 3 টি পদ্ধতির প্রযুক্তিগত পার্থক্য কী? আমি দেখতে পাচ্ছি যে অনেক পরিস্থিতিতে তারা সবাই কাজ করে। আমি তাদের মত সংমিশ্রণ ব্যবহার করে দেখতে .ToList().AsQueryable()

  1. এই পদ্ধতিগুলির অর্থ কী?

  2. কোনও পারফরম্যান্স ইস্যু বা এমন কিছু আছে যা একে অপরকে ব্যবহারের দিকে পরিচালিত করে?

  3. কেন একটি .ToList().AsQueryable()পরিবর্তে , উদাহরণস্বরূপ ব্যবহার করবে .AsQueryable()?


উত্তর:


354

এ সম্পর্কে অনেক কিছুই বলা যায়। আমাকে ফোকাস করতে AsEnumerableএবং AsQueryableউপায়টিতে উল্লেখ ToList()করতে দিন।

এই পদ্ধতিগুলি কী করে?

AsEnumerableএবং AsQueryableঢালাই বা রূপান্তর করতে IEnumerableবা IQueryableযথাক্রমে। আমি বলি castালাই বা কোনও কারণে রূপান্তর :

  • উত্স অবজেক্ট ইতিমধ্যে লক্ষ্য ইন্টারফেস প্রয়োগ করে, উত্স অবজেক্ট নিজেই ফিরে আসে তবে লক্ষ্য ইন্টারফেসে কাস্ট হয়। অন্য কথায়: টাইপটি পরিবর্তিত হয় না, তবে সংকলন-সময় টাইপ হয়।

  • যখন উত্স অবজেক্টটি লক্ষ্য ইন্টারফেসটি প্রয়োগ করে না, উত্স অবজেক্টটি এমন একটি সামগ্রীতে রূপান্তরিত হয় যা লক্ষ্য ইন্টারফেস প্রয়োগ করে। সুতরাং টাইপ এবং সংকলন-টাইপ উভয়ই পরিবর্তন করা হয়।

আমি এটি কিছু উদাহরণ দিয়ে দেখান। আমি এই সামান্য পদ্ধতিটি পেয়েছি যা সংকলন-সময়ের ধরণ এবং কোনও বস্তুর প্রকৃত প্রকারের প্রতিবেদন ( সৌজন্য জন জেন স্কিট ):

void ReportTypeProperties<T>(T obj)
{
    Console.WriteLine("Compile-time type: {0}", typeof(T).Name);
    Console.WriteLine("Actual type: {0}", obj.GetType().Name);
}

আসুন একটি নির্বিচারে লিনাক-টু-এসকিউএল চেষ্টা করি Table<T>, যা প্রয়োগ করে IQueryable:

ReportTypeProperties(context.Observations);
ReportTypeProperties(context.Observations.AsEnumerable());
ReportTypeProperties(context.Observations.AsQueryable());

ফলাফল:

Compile-time type: Table`1
Actual type: Table`1

Compile-time type: IEnumerable`1
Actual type: Table`1

Compile-time type: IQueryable`1
Actual type: Table`1

আপনি দেখতে পাচ্ছেন যে টেবিল শ্রেণি নিজেই সর্বদা ফিরে আসে তবে এর প্রতিনিধিত্ব পরিবর্তন হয়।

এখন একটি বস্তু যে কার্যকরী IEnumerable, না IQueryable:

var ints = new[] { 1, 2 };
ReportTypeProperties(ints);
ReportTypeProperties(ints.AsEnumerable());
ReportTypeProperties(ints.AsQueryable());

ফলাফলগুলো:

Compile-time type: Int32[]
Actual type: Int32[]

Compile-time type: IEnumerable`1
Actual type: Int32[]

Compile-time type: IQueryable`1
Actual type: EnumerableQuery`1

এটা আছে। AsQueryable()অ্যারেটিকে একটিতে রূপান্তরিত করেছে EnumerableQuery, যা " IEnumerable<T>একটি IQueryable<T>ডেটা উত্স হিসাবে সংগ্রহকে উপস্থাপন করে ।" (দুটিই MSDN)।

এর ব্যাবহার কি?

AsEnumerableযে কোনও IQueryableপ্রয়োগ থেকে লিনকিউতে অবজেক্টগুলিতে (এল 2 ও) স্যুইচ করার জন্য প্রায়শই ব্যবহৃত হয় , বেশিরভাগ কারণে যে প্রাক্তন L2O এর কার্যকারিতা সমর্থন করে না। আরও তথ্যের জন্য দেখুন একটি লিনকিউ সত্তায় AsEnumerable () এর প্রভাব কী?

উদাহরণস্বরূপ, একটি সত্ত্বা ফ্রেমওয়ার্ক ক্যোয়ারিতে আমরা কেবলমাত্র একটি সীমিত সংখ্যক পদ্ধতি ব্যবহার করতে পারি। সুতরাং, উদাহরণস্বরূপ, যদি আমাদের কোনও ক্যোয়ারিতে আমাদের নিজস্ব পদ্ধতি ব্যবহার করতে হয় তবে আমরা সাধারণত কিছু লিখি

var query = context.Observations.Select(o => o.Id)
                   .AsEnumerable().Select(x => MySuperSmartMethod(x))

ToList - যা একটি পরিবর্তিত IEnumerable<T>একটি থেকে List<T>- প্রায়ই হিসাবে ভাল এই কাজের জন্য ব্যবহার করা হয়। AsEnumerableবনাম ব্যবহার করার সুবিধাটি ToListহ'ল ক্যোরিটি AsEnumerableকার্যকর করে না। AsEnumerableস্থগিত কার্যকরকরণ সংরক্ষণ করে এবং প্রায়শই অকেজো মধ্যবর্তী তালিকা তৈরি করে না।

অন্যদিকে, যখন একটি লিনকিউ ক্যোয়ারির জোরপূর্বক মৃত্যুদণ্ড কার্যকর করা হয়, ToListতা করার উপায় হতে পারে।

AsQueryableএকটি লভ্য সংগ্রহটি লিনকিউ বিবৃতিতে অভিব্যক্তি গ্রহণ করতে ব্যবহৃত হতে পারে। আরও বিশদের জন্য এখানে দেখুন: সংগ্রহের জন্য আমার কি সত্যই কি এসকিউয়ারেবল () ব্যবহার করা দরকার?

পদার্থের অপব্যবহারের উপর নোট!

AsEnumerableড্রাগ হিসাবে কাজ করে। এটি একটি দ্রুত সমাধান, তবে ব্যয় এবং এটি অন্তর্নিহিত সমস্যাটির সমাধান করে না।

অনেকগুলি স্ট্যাক ওভারফ্লো জবাবগুলিতে, আমি AsEnumerableলোকগুলি লিনকিউ এক্সপ্রেশনগুলিতে অসমর্থিত পদ্ধতিগুলির সাথে যে কোনও সমস্যা সমাধানের জন্য আবেদন করতে দেখি । তবে দাম সবসময় পরিষ্কার হয় না। উদাহরণস্বরূপ, আপনি যদি এটি করেন:

context.MyLongWideTable // A table with many records and columns
       .Where(x => x.Type == "type")
       .Select(x => new { x.Name, x.CreateDate })

... সমস্ত কিছু ঝরঝরে করে একটি এসকিউএল বিবৃতিতে অনুবাদ করা হয়েছে যা ফিল্টার ( Where) এবং প্রকল্পগুলি ( Select)। অর্থাৎ এসকিউএল ফলাফলের সেটের যথাক্রমে দৈর্ঘ্য এবং প্রস্থ উভয়ই হ্রাস পেয়েছে।

এখন ধরুন ব্যবহারকারীরা কেবল তারিখের অংশটি দেখতে চান CreateDate। সত্তা ফ্রেমওয়ার্কে আপনি তা দ্রুত আবিষ্কার করতে পারবেন ...

.Select(x => new { x.Name, x.CreateDate.Date })

... সমর্থিত নয় (লেখার সময়)। আহ, ভাগ্যক্রমে AsEnumerableঠিক আছে:

context.MyLongWideTable.AsEnumerable()
       .Where(x => x.Type == "type")
       .Select(x => new { x.Name, x.CreateDate.Date })

অবশ্যই, এটি চলমান, সম্ভবত। তবে এটি পুরো টেবিলটিকে মেমরির মধ্যে টান দেয় এবং তারপরে ফিল্টার এবং অনুমানগুলি প্রয়োগ করে। ভাল, বেশিরভাগ লোক Whereপ্রথমটি করার মতো যথেষ্ট স্মার্ট :

context.MyLongWideTable
       .Where(x => x.Type == "type").AsEnumerable()
       .Select(x => new { x.Name, x.CreateDate.Date })

তবে তবুও সমস্ত কলামগুলি প্রথমে আনা হয় এবং প্রজেকশনটি মেমোরিতে সম্পন্ন হয়।

আসল ফিক্সটি হ'ল:

context.MyLongWideTable
       .Where(x => x.Type == "type")
       .Select(x => new { x.Name, DbFunctions.TruncateTime(x.CreateDate) })

(তবে এর জন্য আরও কিছুটা বেশি জ্ঞান প্রয়োজন ...)

এই পদ্ধতিগুলি কী করে না?

আইকোয়ারিযোগ্য ক্ষমতা পুনরুদ্ধার করুন

এখন একটি গুরুত্বপূর্ণ সতর্কতা। যখন তুমি কর

context.Observations.AsEnumerable()
                    .AsQueryable()

আপনি উত্স অবজেক্ট হিসাবে উপস্থাপন শেষ হবে IQueryable। (কারণ উভয় পদ্ধতিই কেবল কাস্ট করে এবং রূপান্তর করে না)।

তবে আপনি যখন করবেন

context.Observations.AsEnumerable().Select(x => x)
                    .AsQueryable()

ফলাফল কি হবে?

Selectএকটি উত্পাদন করে WhereSelectEnumerableIterator। এটি একটি অভ্যন্তরীণ। নেট ক্লাস যা প্রয়োগ করে IEnumerable, নাIQueryable । সুতরাং অন্য ধরণের রূপান্তর ঘটেছে এবং পরবর্তীকালে AsQueryableআর কখনও আসল উত্সটি ফিরে আসতে পারে না।

এর নিদর্শনটি হ'ল ব্যবহার AsQueryableকরা কোনও ক্যোয়ার সরবরাহকারীকে তার নির্দিষ্ট বৈশিষ্ট্য সহ একটি গণনাযোগ্য হিসাবে ইনজেক্ট করার উপায় নয় । ধরুন আপনি করেন

var query = context.Observations.Select(o => o.Id)
                   .AsEnumerable().Select(x => x.ToString())
                   .AsQueryable()
                   .Where(...)

শর্তটি কখনই এসকিউএল তে অনুবাদ করা হবে না। AsEnumerable()লিনকিউ বিবৃতি অনুসরণ করার পরে সত্তা ফ্রেমওয়ার্ক ক্যোয়ারী সরবরাহকারীর সাথে সংযোগটি স্থির করে দেয়।

আমি ইচ্ছাকৃতভাবে এই উদাহরণটি দেখাই কারণ আমি এখানে এমন প্রশ্ন দেখেছি যেখানে লোকেরা Includeকল করে কোনও সংকলনে দক্ষতার জন্য 'ইনজেক্ট' করার চেষ্টা করে AsQueryable। এটি সংকলন করে চালিত হয় তবে এটি কিছুই করে না কারণ অন্তর্নিহিত অবজেক্টটির Includeআর বাস্তবায়ন নেই।

এক্সিকিউট

উভয়ই AsQueryableএবং উত্স অবজেক্টটি AsEnumerableকার্যকর (বা গণ্য ) করবেন না । তারা কেবল তাদের ধরণ বা উপস্থাপনা পরিবর্তন করে। উভয় জড়িত ইন্টারফেস, IQueryableএবং IEnumerable, "ঘটতে অপেক্ষা একটি গণনা" ছাড়া আর কিছুই নয়। বাধ্য হয়ে তারা তা করার আগে তাদের মৃত্যুদণ্ড কার্যকর করা হয় না, উদাহরণস্বরূপ, উপরে বর্ণিত হিসাবে, কল করে ToList()

এর অর্থ হ'ল কোনও বস্তুকে IEnumerableডেকে একটি প্রাপ্ত সম্পাদন করাই অন্তর্নিহিত কার্য সম্পাদন করবে । উইলের পরবর্তী ক্রিয়াকলাপ আবার কার্যকর করে । যা খুব ব্যয়বহুল হতে পারে।AsEnumerableIQueryableIQueryableIEnumerableIQueryable

নির্দিষ্ট বাস্তবায়ন

এখনও অবধি, এটি কেবলমাত্র Queryable.AsQueryableএবং Enumerable.AsEnumerableসম্প্রসারণ পদ্ধতি সম্পর্কে ছিল । তবে অবশ্যই যে কেউ একই নামগুলি (এবং ফাংশন) সহ উদাহরণ পদ্ধতি বা এক্সটেনশন পদ্ধতি লিখতে পারেন।

আসলে, একটি নির্দিষ্ট AsEnumerableএক্সটেনশন পদ্ধতির একটি সাধারণ উদাহরণ DataTableExtensions.AsEnumerableDataTableপ্রয়োগ করে না IQueryableবা IEnumerable, তাই নিয়মিত বর্ধনের পদ্ধতি প্রয়োগ হয় না।


উত্তরের জন্য ধন্যবাদ, আপনি দয়া করে ওপি - য় প্রশ্নের উত্তরটি ভাগ করে নিতে পারেন? উদাহরণস্বরূপ, কেন .ToList () .AsQueryable () এর পরিবর্তে AsQueryable () ব্যবহার করা হবে? ?
কেজিজেদেব

@ কিকরাম আমি এমন কিছু ভাবতে পারি না যেখানে এটি কার্যকর হবে। আমি যেমন ব্যাখ্যা করেছি, আবেদন AsQueryable()করা প্রায়শই ভুল ধারনার উপর ভিত্তি করে। তবে আমি কিছুক্ষণের জন্য আমার মাথার পিছনে সিদ্ধ হতে দেব এবং দেখুন যে আমি এই প্রশ্নে আরও কিছু কভারেজ যোগ করতে পারি কিনা।
গার্ট আর্নল্ড

1
দুর্দান্ত উত্তর। আপনি কি দয়া করে যদি আইকুয়ারেবলকে এসইনিউমারেবল () কল করে একনামে একাধিকবার গণনা করা যায় তবে কি হবে তা সুনির্দিষ্ট করে বলতে পারেন? কোয়েরিটি একাধিকবার কার্যকর করা হবে বা ডাটাবেস থেকে ইতিমধ্যে লোড হওয়া ডেটাটি মেমোরিতে পুনরায় ব্যবহার করা হবে?
অ্যান্টনিনোড

@ এনটোনিনোড ভাল ধারণা। সম্পন্ন.
গার্ট আর্নল্ড

46

তালিকা()

  • তাত্ক্ষণিকভাবে জিজ্ঞাসাটি কার্যকর করুন

AsEnumerable ()

  • অলস (পরে কোয়েরিটি কার্যকর করুন)
  • পরামিতি: Func<TSource, bool>
  • অ্যাপ্লিকেশন মেমরিতে প্রতিটি রেকর্ড লোড করুন এবং তারপরে সেগুলি হ্যান্ডেল / ফিল্টার করুন। (উদাহরণস্বরূপ কোথায় / নিন / এড়ান, এটি টেবিল 1 থেকে মেমোরিতে * নির্বাচন করবে, তারপরে প্রথম এক্স উপাদান নির্বাচন করবে) (এই ক্ষেত্রে এটি কী করেছে: লিনাক-টু-এসকিউএল + লিনাক-টু-অবজেক্ট)

AsQueryable ()

  • অলস (পরে কোয়েরিটি কার্যকর করুন)
  • পরামিতি: Expression<Func<TSource, bool>>
  • এক্সপ্রেশনটিকে টি-এসকিউএলে রূপান্তর করুন (নির্দিষ্ট সরবরাহকারীর সাথে), দূরবর্তীভাবে ক্যোয়ারী করুন এবং ফলাফলটি আপনার অ্যাপ্লিকেশন মেমোরিতে লোড করুন।
  • এজন্য ডিবিসেট (সত্তা ফ্রেমওয়ার্কে) দক্ষ কোয়েরি পেতে আইকুয়ারেবলকেও উত্তরাধিকার সূত্রে প্রাপ্ত।
  • প্রতিটি রেকর্ড লোড করবেন না, যেমন ধরুন (5), এটি পটভূমিতে শীর্ষ 5 * এসকিউএল তৈরি করবে। এর অর্থ এই প্রকারটি এসকিউএল ডেটাবেস-এর পক্ষে আরও বন্ধুত্বপূর্ণ এবং এই কারণেই সাধারণত এই ধরণের উচ্চতর কর্মক্ষমতা থাকে এবং কোনও ডাটাবেস নিয়ে কাজ করার সময় এটির প্রস্তাব দেওয়া হয়।
  • তাই AsQueryable()সাধারণত চেয়ে অনেক দ্রুত কাজ করে AsEnumerable()যেমন প্রথমে টি-এসকিউএল, যা আপনার Linq আপনার যেখানে সব শর্ত অন্তর্ভুক্ত উৎপন্ন।

14

ToList () মেমরির সমস্ত কিছু হবে এবং তারপরে আপনি এতে কাজ করবেন। সুতরাং, ToList ()। যেখানে (কিছু ফিল্টার প্রয়োগ করুন) স্থানীয়ভাবে কার্যকর করা হয়। এসকিউয়েরেবল () দূর থেকে সব কিছু চালিয়ে দেবে অর্থাত্ এটির জন্য একটি ফিল্টার ডাটাবেসে প্রেরণ করা হবে। অনুসন্ধানযোগ্য ততক্ষণ আপনি কিছু সম্পাদন করেন না। ToList, তত্ক্ষণাত্ কার্যকর করে।

এছাড়াও, এই উত্তরটি দেখুন কেন তালিকা () এর পরিবর্তে AsQueryable () ব্যবহার করবেন?

সম্পাদনা: এছাড়াও, আপনার ক্ষেত্রে একবার আপনি ToList () করেন তবে পরবর্তী প্রতিটি অপারেশন AsQueryable () সহ স্থানীয় হয়। আপনি স্থানীয়ভাবে চালানো শুরু করার পরে আপনি রিমোটে স্যুইচ করতে পারবেন না। আশা করি এটি এটিকে আরও কিছুটা পরিষ্কার করে তুলবে।


2
"AsQueryable () দূরবর্তীভাবে সবকিছু সম্পাদন করবে" কেবল যদি গণনাযোগ্য ইতিমধ্যে প্রশ্নযোগ্য হয়। অন্যথায়, এটি সম্ভব নয়, এবং সমস্ত কিছু এখনও স্থানীয়ভাবে চলছে। প্রশ্নের ".... ToList ()। AsQueryable ()" রয়েছে, যা আপনার উত্তর, আইএমওতে কিছু স্পষ্টতা ব্যবহার করতে পারে।

2

নীচের কোডে একটি খারাপ পারফরম্যান্সের মুখোমুখি।

void DoSomething<T>(IEnumerable<T> objects){
    var single = objects.First(); //load everything into memory before .First()
    ...
}

সঙ্গে স্থির

void DoSomething<T>(IEnumerable<T> objects){
    T single;
    if (objects is IQueryable<T>)
        single = objects.AsQueryable().First(); // SELECT TOP (1) ... is used
    else
        single = objects.First();

}

একটি আইকিউয়েরেবলের জন্য, সম্ভব হলে আইকোয়ারেবলে থাকুন, আইইনুমারেবলের মতো ব্যবহার না করার চেষ্টা করুন।

আপডেট । এটি আরও একটি সরল করে দেওয়া যেতে পারে ধন্যবাদ গার্ট আর্নল্ডকে

T single =  objects is IQueryable<T> q? 
                    q.First(): 
                    objects.First();
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.