LINQ Tutorial

LINQ Tutorial: LINQ C# 3.0 में Add किया गया सबसे महत्वपूर्ण Addition था। LINQ की वजह से C# में बहुत सारे नए Keywords को Add किया था जो कि C# को बहुत ही Powerful Capabilities Provide करते थे।

LINQ वास्तव में Language Integrate Query का छोटा रूप है। LINQ में उन Features को Define किया गया है, जिनका प्रयोग किसी भी प्रकार के Data Source से Data को Retrieve करने के लिए किया जा सकता है। LINQ इसीलिए सबसे ज्यादा महत्वपूर्ण है क्योंकि Data ही किसी भी Program का मूल आधार होते हैं और LINQ का प्रयोग करके विभिन्न प्रकार के Data Sources से Data को आसानी से Retrieve किया जा सकता है।

सामान्‍यत: Data को कई Formats में Store किया जा सकता है। यानी Data एक XML File के रूप में हो सकता है, Relational Database Tables के रूप में हो सकता है, Spreadsheet के रूप में हो सकता है या किसी अन्‍य Format में हो सकता है। LINQ से पहले इन विभिन्न प्रकार के Data Sources में Stored Data को Retrieve करने के लिए विभिन्न प्रकार के अलग-अलग Syntaxes का प्रयोग करना पडता था।

लेकिन LINQ को C# में Add करने के बाद हम बडी ही आसानी से किसी भी Data Sources से समान Syntax द्वारा Data को Retrieve कर सकते हैं, जबकि ये Syntax भी SQL (Standard Query Language) के समान ही Specify किए जाते हैं।

यानी LINQ हमें ऐसी Capability Provide करता है कि हम LINQ Compatible Data Source पर SQL Queries Generate कर सकते हैं, जो कि पहले केवल किसी Relational Database के लिए ही सम्भव था।

LINQ Compatible Data Source से Data Retrieve करने के लिए हम जो Query Specify करते हैं, वह Query लगभग SQL की Query के समान ही होती है। लेकिन इस Query को किसी Relational Database पर Fire नहीं किया जाताए बल्कि C# के किसी Object पर Fire किया जाता है।

LINQ को हम ठीक उसी प्रकार से XML के साथ Use कर सकते हैं, जिस तरह से इसे SQL Data Source के साथ Use करते हैं और ठीक उसी तरह से हम इसे ADO.NET Datasets के साथ भी Use कर सकते हैं। यानी LINQ के माध्‍यम से हम एक Single Common Language Syntax द्वारा विभिन्न प्रकार के Data Sources से Data की Query कर सकते हैं।

LINQ हमें विभिन्न प्रकार के Data Sources से Query करने के लिए एक Common तरीका Provide करता है। लेकिन इसके अलावा भी LINQ कई तरह के Solutions Provide करता है, जिसे C# में Add किए गए अन्‍य Syntaxes जैसे कि Lambda Expressions, Anonymous Types Extension Methods के साथ भी उपयोग में लिया जा सकता है व विभिन्न प्रकार की Specific Requirements को पूरा किया जा सकता है।

C# के LINQ को हम एक Language के अन्दर दूसरी Language कह सकते हैं। इसलिए LINQ को पूरी तरह से एक Chapter में Describe करना सम्भव नहीं है। बल्कि केवल LINQ पर एक अलग पुस्तक लिखी जा सकती है। क्योंकि LINQ वास्तव में SQL नाम की Query Language का C# Implementation है, जिसका प्रयोग विभिन्न प्रकार के Relational Databases से विभिन्न प्रकार के Data की Query करने के लिए किया जाता है। इसलिए यदि हम चाहें, तो विभिन्न प्रकार की Database Requirements को पूरा करने के लिए LINQ को हम विभिन्न तरीकों से SQL Alternative के रूप में Use कर सकते हैं।

LINQ Tutorial – The Fundamentals

LINQ का Core Concept Query ही है। यानी LINQ को C# में ठीक उसी तरह से विभिन्न प्रकार के Data से Field Objects की Query करने के लिए Use किया जाता है, जिस प्रकार से हम किसी Relational Database की Query करने के लिए SQL Language को Use करते हैं।

एक Query के रूप में हम Data Source से किसी Specific Condition या Criteria के आधार पर Data Retrieve करते हैं और उस Retrieved Data को अपनी जरूरत के अनुसार Access व Manipulate करते हैं। Query विभिन्न प्रकार की हो सकती हैं लेकिन हर प्रकार की Query किसी न किसी तरह का Data Collection ही Return करती है।

एक बार जब हम अपनी जरूरत के आधार पर Query Create कर लेते हैं, उसके बाद उस Query को Execute किया जा सकता है। Query Execute करने का एक तरीका ये है कि हम foreach Loop के अन्दर ही Query को Execute करते हैं और हर Query के Execute होने पर उस Query के Response में कुछ Result Generate होता है।

एक Query को Execute करने में हमेंशा दो Steps Involved होते हैं। पहले Step में Query को Create किया जाता है, जबकि दूसरे Step में उसे Execute किया जाता है। अत: जब हम Query Define करते हैं, तब हम ये बता रहे होते हैं कि हम Data Source से क्या (what) Retrieve करना चाहते हैं और जब हम Query को Execute करते हैं, तब हम Data Source से Actual Data Obtain कर रहे होते हैं।

हम LINQ के माध्‍यम से किसी Data Source से Data को Retrieve कर सकें, इसके लिए जरूरी है कि हम IEnumerable Interface को Implement करें। हम हमारी जरूरत के अनुसार Generic IEnumerable<T> या Non-Generic IEnumerable को Implement कर सकते हैं। जबकि Generic Interface को Implement करते समय हमें System.Collections.Generic Namespace को अपने Program में Import करना जरूरी होता है।

Relational Database System में Data को Normalized Tables के रूप में Organize किया जाता है और Relational Database में विभिन्न Data, Strict Rules को Follow करते हुए Well Organized Tables में Store होते हैं, जिन पर SQL Query Language द्वारा विभिन्न प्रकार की SQL Queries Fire करके इन Tables में Stored Data के Retrieve किया जाता है।

लेकिन C# Program में Data Classes या Structures में Fields के रूप में Store होते हैं, जिनके Data Store करने के तरीके में काफी अन्तर होता है। क्योंकि Structure हमेंशा Stack में Store होता है जबकि Class हमेंशा Heap Area में Space Reserve करता है। परिणामस्वरूप C# 3.0 से पहले इन विभिन्न प्रकार के Data Structures से Data को Retrieve करने का कोई General Query Language Develop नहीं किया जा सका था।

जिसकी वजह से विभिन्न Programming Languages में Data Structures से Data को Retrieve करने के लिए हमेंशा Program का एक Custom Design Part Develop करना पडता है, जिसके माध्‍यम से Objects के Data को Retrieve किया जाता रहा है। इसी समस्या के समाधान के रूप में LINQ को Develop किया गया है जो कि किसी Objects के Collections से Query करने की सुविधा Provide करता है।

LINQ वास्तव में .NET Framework का एक Extension है, जो SQL Query के Similar Queries Create करके C# Programming Language में Data के Collections पर Fire करने की सुविधा Provide करता है। परिणामस्वरूप हम जिस तरह से किसी Relational Database पर SQL Query Fire करके विभिन्न Tables से Specific Criteria के आधार पर Records Retrieve करते हैं, ठीक उसी तरह से हम C# Program में Data के Collections पर SQL Query के समान ही LINQ Query Fire करके Specific Criteria के आधार पर Data Retrieve कर सकते हैं।

LINQ की विशेषता ये है कि हम LINQ Queries का प्रयोग करके न केवल Database से बल्कि Program Objects के Collections से, XML Documents से व अन्‍य प्रकार के Data Source से भी Data को समान प्रकार से Query कर सकते हैं। LINQ की Working को समझने के लिए हम निम्नानुसार एक Simple Program Create कर सकते हैं:

File Name: SimpleLINQExample.cs 
using System;
using System.Linq;

namespace CSharpLINQ
{
    class SimpleQuery
    {
        static void Main()
        {
            int[] numbers = { 1, -2, 3, 0, -4, 5 };

            // Create a query that obtains only positive numbers.
            var posNums = from n in numbers where n > 0 select n;
            Console.Write("The positive values in numbers: ");

            // Execute the query and display the results.
            foreach (int i in posNums) Console.Write(i + " "); 
        }
    }
}

Output:
	The positive values in numbers: 1 3 5

इस Program द्वारा हम LINQ के Basic Concept को आसानी से समझ सकते हैं। इस Program में सबसे पहले हमने अपने Current Program में LINQ सुविधा प्राप्त करने के लिए using Statement का प्रयोग किया है:

using System.Linq;

यदि हम इस Statement को Specify न करें, तो हम हमारे Program में LINQ की सुविधा प्राप्त नहीं कर सकते।

फिर हमने numbers नाम का Integer Type का एक Array Create किया है और उसमें निम्नानुसार तरीके से कुछ Integer Values को Initialize किया है:

int[] numbers = { 1, -2, 3, 0, -4, 5 };

इस Array में कुछ Positive संख्‍याऐं हैं और कुछ Negative संख्‍याऐं हैं। चूंकि C# का Array Implicitly IEnumerable<T> में Convert हो सकता है, इसलिए C# Array को हम LINQ Data Source की तरह Use कर सकते हैं।

फिर जब इस Program के Main() Method का निम्न Statement Execute होता है:

var posNums = from n in numbers 
              where n > 0 
              select n;

तो ये Statement SQL Query के समान तरीके से ही LINQ Query को Represent करता है और numbers नाम के Array से केवल उन Numbers को Retrieve करता है, जो Positive हैं। इस Query में posNums को Query Variable कहा जाता है, जो कि उन Rules के समूह को Refer करता है, जिन्हें Query द्वारा Define किया गया है।

ध्‍यान दें कि हमने इस posNums नाम के Variable को var Keyword के साथ Declare किया है, जो कि Implicitly Typed Variable है। यानी इस Statement के Execution से जिस Type का मान Generate होगा, ये Variable उसी Type का Declare हो जाएगा।

जब हम LINQ Queries Create करते हैं, तब हमारे लिए Implicit तरीके से Query Variable Declare करना ही सुविधाजनक रहता है। हालांकि हम Explicit तरीके से भी इस Query Variable को Declare कर सकते हैं और जब हम Explicit तरीके से Query Variable Declare करते हैं, तब ये जरूरी होता है कि हमारा Variable किसी न किसी तरह से IEnumerable<T> Type का ही हो।

सभी LINQ Queries की शुरूआत from से होती है। ये Clause दो बातें Specify करता है। पहला Range Variable होता है, जो कि Data Source से Element को Retrieve करता है। हमारे उदाहरण के अनुसार n नाम का Variable ही Range Variable है। जबकि दूसरा Data Source को Represent करता है, जो कि हमारे उदाहरण के अनुसार number नाम का Array हमारी इस LINQ Query के लिए Data Source है। from Clause के Syntax को हम निम्नानुसार तरीके से Represent कर सकते हैं:

from RangeVariable in DataSource

LINQ Query का अगले Clause का नाम where Clause होता है। ये Clause उस Condition या Criteria को Represent करता है, जिसे Data Source पर Apply करना होता है। इस Criteria या Condition को Satisfy करने वाले Data ही Data Source से Retrieve होते हैं।

जब हम where Clause Use करते हैं, तब ये जरूरी होता है कि where Clause के बाद Specify किया जाने वाला Expression हमेंशा एक Boolean Value ही Return करे। where Clause को Use करने का Syntax कुछ निम्नानुसार होता है:

where BooleanExpression

इस BooleanExpression को Predicate भी कहते हैं और BooleanExpression के रूप में हम एक से ज्यादा Conditions को Specify कर सकते हैं। हमारे Program के अनुसार समझें तो हमने where Clause को निम्नानुसार तरीके से Specify किया है:

where n > 0

ये Statement इस बात को Indicate करता है कि यदि n का मान 0 से ज्यादा हो, तो ही वह मान Return होकर RangeVariable में Store हो अन्‍यथा नहीं। चूंकि C# के Array में IEnumerator Interface को Implement किया गया होता है, इसलिए LINQ Query Statement एक प्रकार से Enumerator ही Return करता है। यानी Array के सभी Elements को Specified Condition के आधार पर One by One Check करके ही Return करता है।

सरल शब्दों में कहें तो where Clause एक प्रकार से Data Source पर Applied Filter की तरह काम करता है और केवल उन्हीं Elements के मानों को Return करता है, जो इस Filter की Condition को Satisfy करते हैं।

सभी LINQ Queries का अन्त एक select या group Clause से होती है। हमारे Current उदाहरण में हमने select Clause को Specify किया है। ये Clause इस बात को Specify करता है कि हमने LINQ Query के माध्‍यम से क्या Retrieve किया है।

सामान्‍यत: Simple Queries के लिए ये हमेंशा select होता है, क्योंकि हम Data Source से एक Matching Range Value Select करते हैं। select Clause का अन्त हमेंशा एक Semicolon से होता है। लेकिन select Clause के अलावा अन्‍य किसी Clause के साथ Semicolon का प्रयोग नहीं किया जाता।

यदि हम हमारे उदाहरण के आधार पर समझें तो निम्न Statement द्वारा posNums नाम का एक Query Variable Create तो होता है, जिसमें एक LINQ Query Defined होती है:

var posNums = from n in numbers where n > 0 select n;

लेकिन इस Statement तक कोई Result Generate नहीं होता। यानी एक LINQ Query केवल उन Rules को Define करता है, जिनके आधार पर Data Source से Result Return करना होता है। जबकि Result तब तक Generate नहीं होताए जब तक कि हम इस posNums नाम के Query Variable को किसी foreach Looping Construct में Use नही करते हैं।

क्योंकि जैसाकि हमने पहले भी कहा कि LINQ पूरी तरह से Collections के Concept पर आधारित है, जिसमें Enumerator के आधार पर Collection से Result Generate होता है। ठीक उसी Concept के आधार पर हम Query Variable में यहां जो LINQ Query Define करते हैं, वह एक प्रकार से Data Source से Retrieve होने वाले Results का Collection मात्र है और इस Collection में Stored Data तब Retrieve होंगे, जब हम इसे foreach Loop के माध्‍यम से Execute करेंगे।

इसीलिए हमारे इस Program में हमने निम्नानुसार तरीके से एक foreach Loop Create किया है और posNums नाम के Query Variable में Defined LINQ Query के आधार पर Retrieve हो सकने वाले Results को Generate किया है:

foreach (int i in posNums)
Console.Write(i + ” “);

यानी सरल शब्दों में कहें तो posNums वास्तव में एक Collection की तरह है, जिसके हर Enumerator को foreach Loop द्वारा Iterate किया जा रहा है।

परिणामस्वरूप जब इस Program का foreach Loop Run होता है, तो posNums Query Variable में Specified LINQ Rules के आधार पर numbers नाम के Array Data Source से Matching Elements Return होकर posNums में आते हैं और posNums में आने वाले Data को i नाम के Variable में प्राप्त करके Output में Display कर दिया जाता है।

हालांकि हमने हमारे इस foreach Loop में Variable i को Explicitly int Type का Declare किया है, क्योंकि हमें पता है कि हमारा Array Integer Type की Values से Filled है। लेकिन यदि किसी Specific Situation में हमें पता न हो कि Data Source से किस तरह का Data Return हो रहा है, तो उस स्थिति में हम हमारे इस foreach Loop के Variable को निम्नानुसार Implicit तरीके से भी Declare कर सकते हैं:

foreach (var i in posNums)
Console.Write(i + ” “);

जब हम इस तरह से Implicit तरीके का प्रयोग करते हुए foreach Variable i को Declare करते हैं, तो इसका Type Automatically posNums नाम के Collection से Return होने वाले Data के अनुसार Program के Compile Time में Dynamically तय हो जाता है।

चूंकि एक Query Variable केवल LINQ Query के Rules को Define करता है और जब तक हम foreach Loop द्वारा इस Query Variable को Execute नहीं करते, तब तक कोई Actual Result Generate नहीं होता। इसलिए हम एक ही LINQ Query को एक से ज्यादा बार उपयोग में ले सकते हैं। जबकि यदि Data Source का Data Change हो जाता है, तो एक ही बार Define किया गया LINQ Query उसी Data Source से Dynamically अलग-अलग तरह के Result Generate कर सकता है।

इसे समझने के लिए हम हमारे पिछले Program को ही निम्नानुसार तरीके से Modify कर सकते हैं, जिसमें समान LINQ Query को एक से ज्यादा बार उपयोग में लिया गया है और हर बार हमें अलग Result प्राप्त होता है, क्योंकि हमने समान LINQ Query को हर बार Execute करने से पहले Data Source में Stored Data में परिवर्तन कर दिया है:

File Name: UsingSameLINQQueryMoreThenOnce.cs
using System;
using System.Linq;

namespace CSharpLINQ
{
    class SimpleQuery
    {
        static void Main()
        {
            int[] numbers = { 1, -2, 3, 0, -4, 5, 10, };

            // Create a query that obtains only positive numbers.
            var posNums = from n in numbers where n > 0 select n;

            Console.Write("The positive values in numbers: ");

            // Execute the query and display the results.
            foreach (var i in posNums) Console.Write(i + " ");

            // Modifying Data Source 
            numbers[1] = 22;
            numbers[2] = 13;

            Console.Write("\nThe positive values in numbers: ");
            // Execute the query again and display the results.
            foreach (var i in posNums) Console.Write(i + " ");
        }
    }
}

Output:
	The positive values in numbers: 1 3 5
	The positive values in numbers: 1 22 13 5 10

इस Program में हमने LINQ Query को केवल एक ही बार Define किया है। लेकिन जब हम पहली बार foreach Loop को Use करते हैं, तो posNums Collection में केवल 3 Positive Values होते हैं, जिसकी वजह से हमें Output का पहला Result प्राप्त होता है। लेकिन जब हम निम्नानुसार Statements द्वारा numbers Array, जो कि हमारे Program की LINQ Query में Data Source की तरह Use हो रहा है, में दो नए Positive मान Insert कर देते हैं:

            // Modifying Data Source 
            numbers[1] = 22;
            numbers[2] = 13;

तो जब हम दुबारा foreach Loop Execute करते हैं, तो इस बार हमारे Program का Output बदल जाता है। जबकि हमने हमारे LINQ Query को किसी भी तरह से Modify नहीं किया है। ऐसा इसीलिए होता है क्योंकि LINQ Query तब तक Execute नहीं होताए जब तक कि हम foreach Loop Run नहीं होता।

जब हम foreach Loop Run होता है, तो posNums नाम के Query Variable में Stored LINQ Query Rules के आधार पर posNums नाम का Collection Create होता है और Collection Create होते समय हमारे numbers Array में दो नए Items Add हो चुके होते हैं, इसलिए हमें Resultant Output में इस बार दो नए मान और दिखाई देते हैं, जो कि पिछले foreach Loop के Execution के समय numbers नाम के Data Source में नहीं थे।

पिछले दोनों ही उदाहरणों में हमने LINQ Query के Variable n को Explicitly Declare नहीं किया है बल्कि निम्नानुसार इसे सी/ो ही Specify कर दिया है:

var posNums = from n in numbers where n > 0 select n;

ये Variable फिलहाल तो एक Integer Value की तरह Treat होता है क्योंकि इस LINQ Query में Query Variable, Range Variable Data Source Variables हैं, जिनके आधार पर C# Compiler इस बात का पता लगा लेता है कि n किस Data Type का है।

लेकिन ये LINQ Query उसी स्थिति में Normal तरीके से काम कर सकता है, जबकि इसके तीनों ही Variables यानी Query Variable, Range Variable Data Source Variables के बीच Type Agreement हो।

LINQ Query Define करते समय ये जरूरी होता है कि Data Source जिस Type का मान Return करता है, Range Variable उसी Type का हो। इसलिए Range Variable का Type पूरी तरह से Data Source के Data के Type पर निर्भर होता है।

ज्यादातर परिस्थितियों में C#, Range Variable के Type को Data Source के Data के Type के आधार पर Infer कर लेता है। इसलिए हम Range Variable को बिना उसका Type Specify किए हुए भी उपरोक्तानुसार लिख सकते हैं।

साथ ही जब तक Data Source IEnumerable<T> को Implement करता है, C# Type Inference कर सकता है क्योंकि T Data Source के Data के Type को Describe करता है। लेकिन यदि Data Source IEnumerable के किसी Non-Generic Version को Implement करता है, तो उस स्थिति में हमें Range Variable को निम्नानुसार तरीके से Explicitly Declare करना जरूरी होता है:

var posNums = from int n in numbers where n > 0 select n;

हालांकि हमारे Current उदाहरण में हमें Range Variable को Explicitly Declare करने की जरूरत नहीं है। क्योंकि C# के सभी Arrays IEnumerable<T> Type में Convertible होते हैं, जिसकी वजह से Range Variable का Type Infer हो जाते हैं।

LINQ Query द्वारा Return होने वाला Object IEnumerable<T> Type का Instance होता है, जहां T Return होने वाले Element के Type को Represent करता है। अत: Query Variable का Type हमेंशा IEnumerable<T> Type का Instance होना जरूरी होता है। जहां T का Type select Clause के साथ Specified Value के आधार पर तय होता है।

यदि हम हमारे पिछले उदाहरण के आधार पर समझें तो T, int Type का है क्योंकि n, int Type का है। जहां n इसलिए int Type का है, क्योंकि numbers नाम के Array में Stored सभी Elements int Type के हैं। इसलिए यदि हम चाहें तो उपरोक्त Query को Explicitly Type के अनुसार Specify करने के लिए IEnumerable<int> के आधार पर निम्नानुसार लिख सकते हैं:

IEnumerable<int> posNums = from n in numbers where n > 0 select n;

इस Statement का Key Point ये है select Clause द्वारा Selected Items का Type IEnumerable<T> में T के रूप में Passed Type के समान होना चाहिए, जिसे Query Variable Declare करने के लिए Use किया गया है।

सामान्‍यत: Query Variable में Explicitly Type Specify करने के स्थान पर var Keyword को Use किया जाता है क्योंकि ऐसा करने पर Compiler select Clause के आधार पर Query Variable के Type को Proper Type में Infer कर देता है।

जब foreach Loop द्वारा LINQ Query को Execute किया जाता है, तो Iteration करने वाले Variable का Type Exactly वही होना चाहिए, जो select Clause के साथ Specified Variable का होता है। इसलिए यदि हम पिछले उदाहरण के आधार पर यही बात कहें, तो foreach Loop का Variable i, int Type का ही होना चाहिए।

क्योंकि Range Variable n भी int Type का ही है। इसलिए यदि हम चाहें तो इसे var Type का Declare कर सकते हैं, क्योंकि जब posNums से Data Return होगा, तो उस Data के आधार पर ही इस Variable का Type बदल जाएगा।

किसी भी LINQ Query की शुरूआत हमेंशा from Clause से होती है और अन्त हमेंशा select या group Clause पर होता है। जहां select Clause इस बात को निश्चित करता है कि Query द्वारा किस प्रकार के मान को Enumerate किया जा रहा है।

group Clause को Use करने पर Return होने वाले Data एक Group के रूप में Return होते हैं, जहां हर Group को अलग से Enumerate किया जा सकता है। साथ ही where Clause का प्रयोग करके हम Return होने वाले Items को Control करते हैं, जैसाकि हमने हमारे पिछले उदाहरण में किया है।

पिछले उदाहरण में हमने एक Integer Type के Array को Data Source की तरह Use करते हुए LINQ Query Create किया था। ठीक इसी तरह से हम XML, SQL, Datasets, Entities आदि के साथ भी LINQ Queries का प्रयोग कर सकते हैं, जिसे निम्न चित्रानुसार समझा जा सकता है:

LINQ Tutorial - Hindi

C# in Hindiये Article इस वेबसाईट पर Selling हेतु उपलब्‍ध EBook C#.NET in Hindi से लिया गया है। इसलिए यदि ये Article आपके लिए उपयोगी रहा, तो निश्चित रूप से ये पुस्तक भी आपके लिए काफी उपयोगी साबित होगी। 

C#.NET in Hindi | Page:908 | Format: PDF

BUY NOW GET DEMO REVIEWS