Data Mapping in ADO.NET

Data Mapping in ADO.NET: सामान्यत: Database के विभिन्न Objects जैसे कि Tables, Views, Stored Procedures आदि का जो नाम हम Specify करते हैं, वह नाम किसी Application के Frontend के रूप में पूरी तरह से Appropriate नहीं होते।

उदाहरण के लिए हमारे pubs Database की authors Table में Author ID को au_id Specify किया गया है। इसलिए हम जब भी कभी इस Table के Data को DataGridView या अन्य Controls का प्रयोग करते हुए Display करते हैं, तो Output के रूप में हमें हमेंशा au_id ही दिखाई देता है, जबकि Frontend में यदि यही Data “Author ID” Heading के रूप में Show होता, तो ज्यादा बेहतर रहता।

MSSQL Server या Oracle जैसे Database में इस समस्या के समाधान के रूप में हमें AS Keyword Provide करते हैं, जिसे सामान्यत: Aliasing के नाम से जाना जाता है। लेकिन ADO.NET हमें इस समस्या के समाधान के रूप में DataTableMappingDataColumnMapping नाम की दो Classes Provide करता है, जिनके माध्‍यम से हम Underlying Data Source की TablesColumns के नामों को अपने Application के Frontend में Display करने के लिए MAP कर सकते हैं।

Aliasing Mapping में मूल अन्तर यही है कि Aliasing से Underlying Data Source के Column या Table का एक दूसरा नाम Create हो जाता है। जबकि Mapping Objects हमें DataSet Object के ऐसे Data Schema को Manage करने की सुविधा Provide करता है, जिन्हें XML Documents व XML Schemas का प्रयोग करके Create किया गया होता है। साथ ही Aliased Names को हम केवल तभी उपयोगी में ले सकते हैं, जबकि हम Connected Mode में Underlying Database के Objects व Records साथ Interaction कर रहे होते हैं।

सरल शब्दों में कहें तो Aliasing से किसी Resultset के किसी Column के नाम को Rename किया जाता है, Mapping के दौरान दूसरा नाम Create नहीं होता, बल्कि Resultset के किसी Column NameDataColumn Object के साथ One to One का Translation होता है।

जब हम DataSet को Fill करते हैं, तब DataAdapter अपनी स्वयं की TableMappings Property को इस बात के लिए Check करता है कि उसमें किसी Mapping Rule को Specify किया गया है या नहीं। Default रूप से ये Property Empty होती है। इसलिए Underlying Database से आने वाली Tables के Columns का जो नाम होता है, DataSet Object की DataTables Objects के DataColumns का भी वही नाम होता है।

जबकि ADO.NET Mapping को Use करने के लिए हमें DataTableMapping Object Create करना होता है। ये Object हमें एक ही Table के दो नामों को आपस में Map करने की सुविधा देता है। साथ ही ColumnMappings Property, जो कि DataColumnMapping Object का एक Collection होता है, हमें Table के Columns के नामों को Map करने की सुविधा Provide करता है।

जब एक बार हम ये Object Create कर लेते हैं और सभी Required Column Mappings को Create कर लेते हैं, उसके बाद हम इसे DataAdapter की TableMappings Property में Add कर सकते हैं। इस Mapping Mechanism को बेहतर तरीके से समझने के लिए हम अग्रानुसार एक Windows Forms Application Program देख सकते हैं, जिसमें Mapping को एक अलग Method द्वारा Handle किया गया है।

इस Application में सबसे पहले हमने निम्नानुसार एक Form Design किया है, जिस पर एक DataGridView व एक Button Control Exist है:

Data Mapping in ADO.NET - Hindi

जबकि इस Form के Underlying .cs File में लिखा गया हमारा Code निम्नानुसार है:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.Common;
using System.Windows.Forms;

namespace ColumnMappingGUI
{
    public partial class ColumnMapping : Form
    {
        private DataSet dsPubs;
        public ColumnMapping()
        {
            InitializeComponent();
            dsPubs =  new DataSet();
        }

        private void btnFillData_Click(object sender, EventArgs e)
        {
            string conString = "Data Source=.\\SQLSERVEREXPRESS; Initial Catalog =pubs; Integrated Security = true;";

            SqlConnection conPubs = new SqlConnection(conString);
            SqlDataAdapter daPubs = new SqlDataAdapter("SELECT * FROM authors", conPubs);

            MapTheData(daPubs);

            daPubs.Fill(dsPubs, "authors");
            dgvAuthors.DataSource = dsPubs.Tables["authors"];
        }

        private static void MapTheData(SqlDataAdapter da)
        {
            try
            {
               DataColumnMapping authorIDCM = new DataColumnMapping("au_id", "Author ID");
               DataColumnMapping lNameCM = new DataColumnMapping("au_lname", "Last Name");
               DataColumnMapping fNameCM = new DataColumnMapping("au_fname", "First Name");
               DataColumnMapping phoneCM = new DataColumnMapping("phone", "Phone No.");
               DataColumnMapping addressCM = new DataColumnMapping("address", "Address");
               DataColumnMapping cityCM = new DataColumnMapping("city", "City");
               DataColumnMapping stateCM = new DataColumnMapping("state", "State");
               DataColumnMapping zipCM = new DataColumnMapping("zip", "Pincode");
               DataColumnMapping contactCM = new DataColumnMapping("contract", "Contact No.");

                DataTableMapping authorsMapping = new DataTableMapping("authors", "Authors");
                authorsMapping.ColumnMappings.Add(authorIDCM);
                authorsMapping.ColumnMappings.Add(lNameCM);
                authorsMapping.ColumnMappings.Add(fNameCM);
                authorsMapping.ColumnMappings.Add(phoneCM);
                authorsMapping.ColumnMappings.Add(addressCM);
                authorsMapping.ColumnMappings.Add(cityCM);
                authorsMapping.ColumnMappings.Add(stateCM);
                authorsMapping.ColumnMappings.Add(zipCM);
                authorsMapping.ColumnMappings.Add(contactCM);

                da.TableMappings.Add(authorsMapping);
            }
            catch (Exception e)
            {
                Console.WriteLine("Error:" + e.Message);
            }
        }
    }
}

जब हम इस Application को Run करते हैं, तो सबसे पहले निम्नानुसार Code Execute होता है:

        private DataSet dsPubs;
        public ColumnMapping()
        {
            InitializeComponent();
            dsPubs =  new DataSet();
        }

ये Code हमारे Form की Class में dsPubs नाम का एक नया DataSet Object Declare करता है और उस Object को Form के Constructor में Memory Allocate करता है। परिणामस्वरूप हमें हमारा Output Form उपरोक्त चित्रानुसार दिखाई देने लगता है।

जब हम इस Form पर दिखाई देने वाले “Fill Data” Button पर Click करते हैं, तब इस Button के साथ Associated Event Handler Execute होता है, जो कि निम्नानुसार Codes के माध्‍यम से Underlying Data Source से Connection Establish करता है और authors नाम की Table के Data को daPubs नाम के DataAdapter Object के माध्‍यम से Retrieve करने के लिए Setup करता है:

       string conString = "Data Source=.\\SQLSERVEREXPRESS; Initial Catalog =pubs; Integrated Security = true;";

        SqlConnection conPubs = new SqlConnection(conString);
        SqlDataAdapter daPubs = new SqlDataAdapter("SELECT * FROM authors", conPubs);

DataAdapter Setup होने के बाद निम्न Statement के माध्‍यम से MapTheData() नाम का Method Execute होता है, जिसमें Parameter के रूप में DataAdapter Object को Pass किया गया है:

MapTheData(daPubs);

इस Method को DataAdapter Object के माध्‍यम से DataSet Object को Fill करने से पहले इसीलिए Call किया गया है, क्योंकि ये Method Underlying DataSource से आने वाली Table के Columns के नामों को DataSet Object में Create होने वाले DataTables Object के Columns के नए नामों से Map करने का काम करता है। इस Method के Execute होते ही एक try Block में निम्नानुसार Codes Execute होते हैं:

       DataColumnMapping authorIDCM = new DataColumnMapping("au_id", "Author ID");
       DataColumnMapping lNameCM = new DataColumnMapping("au_lname", "Last Name");
       DataColumnMapping fNameCM = new DataColumnMapping("au_fname", "First Name");
       DataColumnMapping phoneCM = new DataColumnMapping("phone", "Phone No.");
       DataColumnMapping addressCM = new DataColumnMapping("address", "Address");
       DataColumnMapping cityCM = new DataColumnMapping("city", "City");
       DataColumnMapping stateCM = new DataColumnMapping("state", "State");
       DataColumnMapping zipCM = new DataColumnMapping("zip", "Pincode");
       DataColumnMapping contactCM = new DataColumnMapping("contract", "Contact No.");

ये Codes DataColumnMapping Class का एक Object Create करते हैं और इस Class के Constructor के माध्‍यम से Underlying Database की Tables के Columns के नामों को एक नए नाम से Map करते हुए उसके Reference को Newly Create होने वाले Object में Store कर देते हैं।

DataColumnMapping Objects Underlying Table व DataSet Object की DataTable दोनों के Columns के नामों को One-to-One Form में Map करते हैं। इन Objects को Create करते समय इनके Constructor में पहले Parameter के रूप में हमें Actual Database Column का नाम Specify करना होता है और दूसरे Parameter के रूप में हम उस नाम को Specify करते हैं, जिसे हम DataSet Object में DataTable के ColumnName के रूप में Map करना चाहते हैं।

चूंकि हम हमारी authors नाम की Table के Columns के नामों के लिए नए नाम Map करना चाहते हैं, इसलिए उपरोक्तानुसार विभिन्न Columns को एक Specific नाम Map किया है, जो कि Frontend Application पर User के सामने Display होता है।

जरूरी नहीं है कि हम हमारे Underlying Database Table के सभी Columns को नया Name Assign करें। जिन Columns के साथ हम उपरोक्तानुसार नया नाम Map नहीं करते, DataSet की DataTables के उन DataColumns के नाम वही होते हैं, जो Underlying Table के Columns के नाम होते हैं।

जब एक बार हम वांछित Columns के लिए DataColumnMapping Objects को Define कर लेते हैं, उसके बाद हमें एक DataTableMapping Object Create करना होता है और इस Object में उपरोक्तानुसार Create किए गए विभिन्न Mapping Objects को Add करना होता है। इस जरूरत को पूरा करने के लिए हमने हमारे इस Example Program के MapTheData() Method में निम्न Statement Specify किया है:

DataTableMapping authorsMapping = new DataTableMapping(“authors”, “Authors”);

ये Statement authorsMapping नाम का DataTableMapping Type का एक Object Create करता है। DataTableMapping Type का Constructor भी दो Parameters Accept करता है, जहां पहला Parameter, Underlying Database की Source Table के नाम को Case Sensitive Form में Accept करता है।

इसी नाम को हमें DataSet Object को DataAdapter के माध्‍यम से Data Fill करते समय यानी Fill() Method का प्रयोग करते समय दूसरे Fill() Method के दूसरे Parameter के रूप में Specify करना होता है। जबकि यदि हम इस Constructor में किसी Source Table का नाम Specify न करें, तो फिर Fill() Method का प्रयोग करते समय दूसरे Parameter के रूप में हमें Default Table Name को Specify करना जरूरी होता है।

इस Method के दूसरे Parameter के रूप में हम जो नाम Specify करते हैं, वह नाम DataSet Object में Create होने वाले DataTable Object के साथ Set हो जाता है। जबकि यदि हम इस Constructor में कोई Parameter Specify नहीं करते, तो DataSet Object में Create होने वाले DataTable Object का वही नाम होता है, जो Underlying Database की Table का होता है।

इस DataTable Mapping Object में ColumnMappings नाम का एक Collection होता है, जिसमें हमें उन सभी Columns को Add करना होता है, जिसे हम Database से DataSet में नए नाम के साथ Map करना चाहते हैं।

इसलिए authorsMapping नाम के अपने DataColumnMapping Type के Object में अपने सभी DataColumnMapping Objects को Add करने के लिए हमने निम्नानुसार Statements का प्रयोग किया है:

                authorsMapping.ColumnMappings.Add(authorIDCM);
                authorsMapping.ColumnMappings.Add(lNameCM);
                authorsMapping.ColumnMappings.Add(fNameCM);
                authorsMapping.ColumnMappings.Add(phoneCM);
                authorsMapping.ColumnMappings.Add(addressCM);
                authorsMapping.ColumnMappings.Add(cityCM);
                authorsMapping.ColumnMappings.Add(stateCM);
                authorsMapping.ColumnMappings.Add(zipCM);
                authorsMapping.ColumnMappings.Add(contactCM);

सभी DataColumnMapping Objects को authorsMapping नाम के DataTableMapping Object में Add करने के बाद अन्त में हमने निम्न Statement का प्रयोग करते हुए इस DataTableMapping Object को अपने Program के DataAdapter Object की TableMappings Property में Add किया है:

da.TableMappings.Add(authorsMapping);

चूंकि हम सभी Column Mapping Related Logics को एक User Defined Method में Specify कर रहे हैं, इसलिए इस Method में अपने Main Program के DataAdapter Object के Reference को प्राप्त करने के लिए ही इस Method को Call करते समय हमने अपने DataAdapter Object को निम्नानुसार तरीके से Parameter के रूप में Pass किया था-

MapTheData(daPubs);

यानी Main Program का daPubs जिस Memory Location को Refer कर रहा है, हमारे MapTheData() Method में निम्नानुसार तरीके से Parameter Accept करने के लिए Specify किया गया da नाम का Object भी उसी Memory Location को Refer कर रहा है।

इसलिए जब हम इस Object की TableMappings Property में DataTableMapping Object को Add करते हैं, तो वास्तव में हम अपने Main Program के daPubs Object की TableMappings Property में ही DataTableMapping Object को Add कर रहे होते हैं।

चूंकि हमने इस Method में जो भी Code लिखा है, उसे एक try Block में Enclose किया है। इसलिए यदि किसी प्रकार का कोई Error या Exception Trigger होता है, तो उसे Handle करने के लिए catch Block Execute हो जाता है और Trigger होने वाली Error या Exception की जानकारी एक Message के रूप में Output में Display कर देता है।

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

daPubs.Fill(dsPubs, “authors”);

ये Statement Execute होते ही “authors” नाम की Database Table के Data को dsPubs नाम के DataSet Object में Fill करता है। लेकिन जब DataSet Object को Data से Fill करने से पहले ये Object अपनी TableMappings Property को Check करता है, तो उसमें DataTableMapping Object Exist होता है। जिसकी वजह से DataAdapter Underlying Database के Table के Data को DataSet Object में Fill करते समय Actual Table के Column Names को Use न करते हुए DataSet Object के लिए DataTable Object Create करते समय Map किए गए Column Names को Use करता है। अन्त निम्न Code Execute होता है:

dgvAuthors.DataSource = dsPubs.Tables[“authors”];

ये Code DataSet Object की “authors” नाम की Table के Data से Form पर स्थित DataGridView Control को Fill कर देता है। परिणामस्वरूप हमें Resultant Output Form कुछ निम्नानुसार दिखाई देता है:

Data Mapping in ADO.NET - Hindi

जहां हम देख सकते हैं कि इस बार DataGridView Control की Heading Row में Columns का नाम वह दिखाई नहीं दे रहा है, जो कि Underlying Table के Columns का नाम होता है, बल्कि इस बार दिखाई देने वाले नाम वे नाम हैं, जिन्हें हमने MapTheData() Method में Mapping के लिए Specify किया है।

हालांकि उपरोक्त Program में MapTheData() Method की Coding बहुत ज्यादा है। लेकिन हम उपरोक्त Code को ही निम्नानुसार Short तरीके से भी Specify कर सकते हैं:

        private static void MapTheData(SqlDataAdapter da)
        {
            try
            {
                DataColumnMapping[] mappedColumns = { 
                    new DataColumnMapping("au_id", "Author ID"), 
                    new DataColumnMapping("au_lname", "Last Name"),
                    new DataColumnMapping("au_fname", "First Name"),
                    new DataColumnMapping("phone", "Phone No."),
                    new DataColumnMapping("address", "Address"),
                    new DataColumnMapping("city", "City"),
                    new DataColumnMapping("state", "State"),
                    new DataColumnMapping("zip", "Pincode"),
                    new DataColumnMapping("contract", "Contact No.")
                };

                DataTableMapping authorsMapping = new DataTableMapping("authors", "Authors", mappedColumns);
                
                da.TableMappings.Add(authorsMapping);
            }
            catch (Exception e)
            {
                Console.WriteLine("Error:" + e.Message);
            }
        }

इस Modified Method में हमने DataColumnMapping Objects का mappedColumns नाम का एक Array Create कर लिया है, जिसका हर Element Underlying Database की Table के एक Column को Map करता है। फिर हमने DataTableMapping Constructor के ऐसे Version को Use किया है, जो तीन Parameters Accept करता है और तीसरे Parameter के रूप में हमने इस MappedColumns Object को Specify कर दिया है। जिसकी वजह से हमें हर DataColumnMapping Object को DataTableMapping Object में अलग-अलग Add करने की जरूरत नहीं पडती।

कई बार हमें किसी Table के केवल एक या दो Columns को ही Map करना होता है। इस प्रकार की जरूरत होने पर हमें उपरोक्तानुसार पूरा Separate Method Create करने की जरूरत नहीं होती। बल्कि हम चाहें तो निम्नानुसार तरीके से सीधे ही DataTableMapping Object Create करके उसकी TableMappings Property में Map किए जाने वाले Tables को Add कर सकते हैं और फिर इस DataTableMapping Object को सीधे ही DataAdapter Object की ColumnMappings Property को Assign कर सकते हैं। जैसे:

            DataTableMapping mapColumn = new DataTableMapping();
            daPubs.TableMappings.Add("authors", "Authors");

            mapColumn.ColumnMappings.Add("au_id", "Author ID");
            mapColumn.ColumnMappings.Add("lname", "Last Name");
            mapColumn.ColumnMappings.Add("fname", "First Name");

इस Code में हमने Main Program में ही DataTableMapping Type का mapColumn नाम का एक Object Create किया है और इस Object को अपने DataAdapter Object daPubs की TableMapping Property में Add कर दिया है। Add करने के बाद इस DataTableMapping Object mapColumn की ColumnMappings Property में au_id, lname fname नाम के तीन Database Columns के लिए Mapping Names को Add कर दिया है।

Object Oriented Programming System पर आधारित C# या VB.NET जैसी Programming Languages में हम किसी एक ही जरूरत को पूरा करने के लिए कई तरीकों को Use कर सकते हैं, जो कि हमारे लिए एक प्रकार की Flexibility तो Provide करता है, लेकिन कई बार यदि इन Programming Languages व Object Oriented Programming System का अच्छा ज्ञान न हो, तो एक ही काम को पूरा करने के लिए Use किए जा सकने वाले विभिन्न तरीके कई बार काफी Confusion भी पैदा करते हैं।

इस प्रकार की Confusion वाली स्थिति पैदा न हो, इसके लिए हम यहां एक उदाहरण द्वारा इस बात को समझने की कोशिश करेंगे कि किस तरह से हम एक ही काम को कई तरीकों से कई प्रकार के Code Statements लिखकर पूरा कर सकते हैं।

पिछले उदाहरण में हमने कुल तीन तरीकों से Mapping करने के बारे में जाना। Mapping करने के लिए हम इन तीन तरीकों के अलावा और भी कई तरीके उपयोग में ले सकते हैं। चलिए, इस Mapping के Code द्वारा ही इस बात को समझने की कोशिश करते हैं।

DataAdapter Object हमें Mapping Objects को अपनी TableMappings Property में Add करने की सुविधा देता है और इस Object में हम DataTableMapping Type के Object को Add कर सकते हैं, जो कि एक Single Table को Represent करता है। ये DataTableMapping Object हमें नया Column Mapping Add करने के लिए ColumnMappings नाम की Property Provide करता है, जिसमें हम DataColumnMapping Type के Object को Add कर सकते हैं, जहां हर DataColumnMapping Object एक Mapped Column को Represent करता है।

यानी मूल रूप से तो हमें DataAdapter Object में TableMapping Object ही Add करना है। जबकि इस Property में कई TableMappings Object Add हो सकते हैं और हर TableMappings Object में कई ColumnMappings Objects Add हो सकते हैं।

Object Oriented Programming Language C# में किसी Object के हमेंशा दो हिस्से होते हैं। पहला हिस्सा Stack में Create होता है जबकि दूसरा हिस्सा Heap Area में Create होता है। Heap Area Actual Memory यानी RAM का वह हिस्सा होता है, जहां Object का Actual Data Store होता है। जबकि इस Actual Area का Address या Reference, Stack में Store होता है, जो कि Actual Data को Refer करता है। इसलिए जब हम किसी Object को Declare करते हैं, तो वास्तव में हम केवल Stack Area में एक Reference Store करने के लिए ही Space Reserve कर रहे होते हैं। जैसे:

DataTableMapping mapColumn;

ये Statement DataTableMapping Type के एक Actual Memory Area के Address को Hold करने के लिए Memory के Stack में Space Reserve करता है, जिसका नाम mapColumn होता है। लेकिन बिना Memory Allocate किए हुए हम इस Object में कोई Value Store नहीं कर सकते। यानी यदि हम इस Statement के Just बाद में निम्न Statement लिखें-

mapColumn.ColumnMappings.Add(“au_id”, “Author ID”);

तो C# Compiler हमें Error ही Return करेगा। क्योंकि हमने Heap Area में Reserve होने वाले किसी Actual Memory Location का Address Store करने के लिए mapColumn नाम का DataTableMapping Type का Reference Variable तो Create कर लिया है, लेकिन Actual Heap Area अभी तक Reserve नहीं किया है, जिसमें इस DataTableMapping Type के Object का Actual Data Store होता है और Heap Area में Actual Memory Location Reserve करने का काम new Operator करता है। इसीलिए जब हम निम्नानुसार Statement लिखते हैं:

DataTableMapping mapColumn = new DataTableMapping();

तब हम वास्तव में दो काम कर रहे होते हैं। पहले काम के अन्तर्गत हम DataTableMapping mapColumn; Statement द्वारा Stack Area में DataTableMapping Type के Heap Area के Actual Memory Address को Hold करने के लिए Memory के Stack Area में Memory Reserve कर रहे होते हैं, जिसे पूरे Program के दौरान mapColumn नाम से Identify किया जाता है।

जबकि दूसरे काम के अन्तर्गत हम new DataTableMapping(); Statement द्वारा Heap Area में Actual Memory भी Reserve कर रहे होते हैं और इस Newly Reserve होने वाली Memory का Address mapColumn नाम के Reference Variable में Store कर रहे होते हैं। यानी एक Single Object Creation भी वास्तव में 2-Step Process होता है। इसलिए इन दोनों Steps को हम निम्नानुसार तरीके से अलग-अलग भी लिख सकते हैं:

DataTableMapping mapColumn;
mapColumn = new DataTableMapping();

चूंकि हम जब भी कभी new Operator का प्रयोग करते हुए Actual Memory Area Reserve करते हैं, तब उस Newly Reserved Memory Area का एक Reference यानी Address Return होता है, जिसे किसी न किसी Variable में Store करना जरूरी होता है।

इसीलिए उपरोक्त दूसरी Line के Code में हमने new DataTableMapping(); Statement के Execution से Return होने वाले Heap Area Address को Assignment Operator का प्रयोग करके mapColumn नाम के Stack Area Variable में Store किया है, ताकि जब भी कभी हमें इस Heap Area के Data को Access करने की जरूरत हो, हम mapColumn नाम द्वारा उस Heap Area को Access कर सकें।

हालांकि हमेंशा ये जरूरी होता है कि new Operator द्वारा Create होने वाले Memory Area के Address को किसी Stack Area के Reference Variable में Store किया जाए, लेकिन हमेंशा ऐसा जरूरी नहीं होता कि हम Stack Area Variable को Create करके ही उसमें इस Address के Store करें।

बल्कि जब हम किसी Method को Call करते हैं, जो कि Parameter के रूप में DataTableMapping Type के Object का Reference Hold करता है, तो हम वास्तव में इस Reference Accept करने वाले Variable में भी new Operator के माध्‍यम से Create होने वाले Object यानी Heap Area Memory के Address को Assign कर सकते हैं।

इसलिए जैसाकि हमने Discussion की शुरूआत में बताया कि Mapping Create करने के लिए हमें DataAdapter Object की TableMapping Property में DataTableMapping Object को Add करना होता है, इसका मतलब ये नहीं है कि हम पहले DataTableMapping Type का एक Object Create करें और फिर उस Object को DataAdapter की TableMapping Property में Add करें। क्योंकि यदि हम DataAdapter की TableMapping Property में DataTableMapping Object को Add करने वाले Method का Syntax देखें, तो ये कुछ निम्नानुसार होता है:

Data Mapping in ADO.NET - Hindi

इस Syntax को सरल तरीके से हम निम्नानुसार भी लिख सकते हैं:

int DataTableMappingCollection.Add(object value)

यानी Add() Method Parameter के रूप में एक Object Type का Parameter Accept करता है और आने वाले Argument को Hold करने के लिए निम्न Statement के माध्‍यम से Memory के Stack Area में object type का value नाम का एक Local Reference Variable Create करता है, जो कि केवल इस Add() Method के Scope में ही Available रहता है:

object value;

अब जब तक हम इस object Type के value नाम के Variable में किसी Heap Area Memory का Address Assign न करें, तब तक ये Reference Variable किसी Actual Object को Refer नहीं करता। लेकिन जब हम इस Add() Method में Table के नाम के रूप में निम्नानुसार एक String Specify करते हैं:

daPubs.TableMappings.Add(“authors”);

तो C# इस String को Memory के Heap Area में Store करता है और उस Heap Area का Base Address या Reference Return करता है, जो कि पिछले Statement के Execution से Create होने वाले value नाम के Variable को Initialize हो जाता है। यानी यदि हम सरल Statement के रूप में लिखें, तो इस Add() Method में String के रूप में Table का नाम Specify करने पर Execute होने वाला Statement निम्नानुसार ही होता है:

object value = “authors”;

जबकि यदि हम इस String Type के Object को new Operator का प्रयोग करते हुए Memory Allocate करना चाहते, तो हमें उपरोक्त Statement को निम्नानुसार Specify करना होता-

object value = new String(“authors”);

हम समझ सकते हैं कि Object Oriented Programming System के लिहाज से ये एक Valid Statement है, हालांकि C# में ये Statement Error Generate करता है। लेकिन जो Process उपरोक्त Statement के Execute होने से Follow होता है, वही Process तब Follow होता है, जब हम अपने Add() Method में इसी तरीके से निम्नानुसार इस String Object को Specify करते हैं:

daPubs.TableMappings.Add(new String(“authors”));

यानी जब ये Statement Execute होता है, तब Parameter के रूप में String Pass होने से पहले Memory के Heap Area में String को Store करने के लिए Memory Reserve होता है और क्योंकि हमने new Operator को Use किया है, इसलिए इस Heap Area का Base Address या Reference Return होता है और उस Reference को Hold करने के लिए जिस Stack Area के Local Variable की जरूरत है, उसे Add() Method के Call होते ही C# Compiler द्वारा object value के रूप में Declare कर दिया जाता है।

परिणामस्वरूप जब नया String Object Create होता है, तो उसका Reference इस value नाम के Reference Variable में Store हो जाता है और पूरे Block के दौरान इस String को value नाम के Object Variable द्वारा Access किया जा सकता है। हालांकि C# में उपरोक्त Statement Error Generate करता है, लेकिन ये एक Valid Statement है और सभी Object Oriented Programming Languages जैसे कि Java में इसी तरह से काम करता है।

इसलिए जब हम उपरोक्तानुसार तरीके से किसी Method में Parameter के रूप में किसी Object का Reference Pass करना चाहते हैं, तो जरूरी नहीं है कि हम पहले उस New Object का Reference एक Local Variable में Store करें और उस Local Variable को Method में Parameter की तरह Pass करें। जैसे:

        private static void MapTheData(SqlDataAdapter da)
        {
            try
            {
               DataColumnMapping authorIDCM = new DataColumnMapping("au_id", "Author ID");
               DataColumnMapping lNameCM = new DataColumnMapping("au_lname", "Last Name");
               DataColumnMapping fNameCM = new DataColumnMapping("au_fname", "First Name");
               DataColumnMapping phoneCM = new DataColumnMapping("phone", "Phone No.");
               DataColumnMapping addressCM = new DataColumnMapping("address", "Address");
               DataColumnMapping cityCM = new DataColumnMapping("city", "City");
               DataColumnMapping stateCM = new DataColumnMapping("state", "State");
               DataColumnMapping zipCM = new DataColumnMapping("zip", "Pincode");
               DataColumnMapping contactCM = new DataColumnMapping("contract", "Contact No.");

                DataTableMapping authorsMapping = new DataTableMapping("authors", "Authors");
                authorsMapping.ColumnMappings.Add(authorIDCM);
                authorsMapping.ColumnMappings.Add(lNameCM);
                authorsMapping.ColumnMappings.Add(fNameCM);
                authorsMapping.ColumnMappings.Add(phoneCM);
                authorsMapping.ColumnMappings.Add(addressCM);
                authorsMapping.ColumnMappings.Add(cityCM);
                authorsMapping.ColumnMappings.Add(stateCM);
                authorsMapping.ColumnMappings.Add(zipCM);
                authorsMapping.ColumnMappings.Add(contactCM);

                da.TableMappings.Add(authorsMapping);
            }
            catch (Exception e)
            {
                Console.WriteLine("Error:" + e.Message);
            }
        }

बल्कि इसी Method के Codes को हम निम्नानुसार भी लिख सकते हैं:

 private static void MapTheData(SqlDataAdapter da)
 {
   try
   {
   DataTableMapping authorsMapping = new DataTableMapping("authors", "Authors");
   authorsMapping.ColumnMappings.Add(new DataColumnMapping("au_id", "Author ID"));
   authorsMapping.ColumnMappings.Add(new DataColumnMapping("au_lname", "Last Name"));
   authorsMapping.ColumnMappings.Add(new DataColumnMapping("au_fname", "First Name"));
   authorsMapping.ColumnMappings.Add(new DataColumnMapping("phone", "Phone No."));
   authorsMapping.ColumnMappings.Add(new DataColumnMapping("address", "Address"));
   authorsMapping.ColumnMappings.Add(new DataColumnMapping("city", "City"));
   authorsMapping.ColumnMappings.Add(new DataColumnMapping("state", "State"));
   authorsMapping.ColumnMappings.Add(new DataColumnMapping("zip", "Pincode"));
   authorsMapping.ColumnMappings.Add(new DataColumnMapping("contract", "Contact No."));

   da.TableMappings.Add(authorsMapping);
   }
   catch (Exception e)
   {
     Console.WriteLine("Error:" + e.Message);
   }
 }

जैसाकि हम इस Modified Method में देख सकते हैं कि इस Method में भी हमने विभिन्न Columns को Map करने के लिए DataColumnMapping Type के Objects Create किए हैं, लेकिन उनका Reference Stack में Created किसी Reference Variable में Store करके उस Reference Variable को DataTableMapping Object के ColumnMappings Property में Add नहीं किया है, बल्कि DataColumnMapping Object Create करते ही उससे Return होने वाले Heap Area Address को सीधे ही DataTableMapping Object की ColumnMappings Property के Collection में Add कर दिया है।

जब हम इस तरह का DataColumnMapping Object Create करते हैं, तो इस प्रकार से Create किए गए किसी भी Object को Anonymous Object कहा जाता है, क्योंकि ऐसे Objects का कोई नाम नहीं होता। साथ ही इस प्रकार के Objects केवल उसी Block या Method के लिए ही उपयोगी होते हैं, जिनमें इन्हें Parameter की तरह Pass किया जाता है। इसलिए इन Objects को केवल एक ही बार उपयोग में लिया जाता है। परिणामस्वरूप इन्हें Single Time Object या One Time Object भी कहते हैं।

इस प्रकार का Anonymous Object Create करने का एक फायदा ये भी होता है कि हमें अलग से Reference Hold करने वाला Variable Declare करने की जरूरत नहीं होती। परिणामस्वरूप Memory की बचत होती है। साथ ही ये Object Single Time Use होने के बाद Memory Release कर देते हैं, इसलिए इस प्रकार के Program की Performance ज्यादा अच्छी होती है। साथ ही हमारे Program की Size भी कम होती है, क्योंकि हमें कम Codes Type करने पडते हैं।

यदि हम चाहें तो इसी Method के Codes को थोडा और कम करने के लिए इसे निम्नानुसार तरीके से और Modify कर सकते हैं:

        private static void MapTheData(SqlDataAdapter da)
        {
            try{
                DataTableMapping authorsMapping = new DataTableMapping("authors", "Authors");
                var map = authorsMapping.ColumnMappings;
                map.Add(new DataColumnMapping("au_id", "Author ID"));
                map.Add(new DataColumnMapping("au_lname", "Last Name"));
                map.Add(new DataColumnMapping("au_fname", "First Name"));
                map.Add(new DataColumnMapping("phone", "Phone No."));
                map.Add(new DataColumnMapping("address", "Address"));
                map.Add(new DataColumnMapping("city", "City"));
                map.Add(new DataColumnMapping("state", "State"));
                map.Add(new DataColumnMapping("zip", "Pincode"));
                map.Add(new DataColumnMapping("contract", "Contact No."));

                da.TableMappings.Add(authorsMapping);
            }
            catch (Exception e) {
                Console.WriteLine("Error:" + e.Message);
            }
        }

इस Code में हमने केवल एक Line के नए Code को Add किया है, जो कि निम्नानुसार है:

var map = authorsMapping.ColumnMappings;

ये Statement लिखने से map नाम के Reference Variable में वह authorsMapping. ColumnMappings नाम के Collection Object का Reference Store हो जाता है। इसलिए हम इतना बडा Statement लिखने के स्थान पर केवल map नाम का प्रयोग भी कर सकते हैं, जिसका Type ColumnMapping Collection के Type के समान ही होता है क्योंकि हमने var Statement का प्रयोग किया है। यानी जहां कहीं पर भी हमें authorsMapping. ColumnMappings को Use करने की जरूरत हो, हम हमारे Program में इसके Alias map नाम को भी Use कर सकते हैं।

इस प्रकार से हम समझ सकते हैं कि एक ही जरूरत को पूरा करने के लिए Object Oriented Programming System के माध्‍यम से C# हमें कई तरीके Provide करता है और हम जिस तरीके को चाहें, अपनी सुविधानुसार उसे उपयोग में लेकर अपनी जरूरत को पूरा कर सकते हैं।

MissingMappingAction and MissingSchemaAction

जैसाकि उपरोक्त Discussion से हमने समझा कि जब DataAdapter Object, DataSet Object को Underlying Database से आने वाले Data से Fill करता है, तो Fill करने से पहले ये इस बात को Check करता है कि किस Table के लिए Mapping को Specify किया गया है। यदि किसी Table के लिए कोई Mapping Specify न किया गया हो, तो ये DataSet की सभी DataTables को उनके Original नामों को Use करते हुए Fill कर देता है।

लेकिन जिन Tables के Columns के लिए हमने Mapping को Specify नहीं किया है, उनके लिए भी हम DataAdapter को Configure कर सकते हैं, कि ऐसे Unspecified Column Mappings वाले Columns के साथ किस प्रकार का Treatment करना है और इस जरूरत को पूरा करने के लिए हम DataAdapter Object की MissingMappingAction Property को Use कर सकते हैं, जिसकी तीन Settings होती हैं:

Passthrough Setting

ये Default Setting होती है, Mapping Specify न होने की स्थिति में DataAdapter Object, DataSet Object में Create होने वाली DataTables के DataColumns का नाम, Underlying Database की Table के Columns के समान Set कर देता है।

Error Setting

इस Setting को Specify करने पर, Mapping Specify न होने की स्थिति में DataAdapter Object, System.Exception Raise करता है।

Ignore Setting

इस Setting को Specify करने पर, Mapping Specify न होने की स्थिति में DataAdapter Object, उस Column को Ignore कर देता है। परिणामस्वरूप Unspecified Mapping वाले Columns, DataSet Object के DataTable Object में Exist नहीं होते।

साथ ही जब हम Fill() या Update() Method Use करते हैं, तो इन Methods को Use करते समय ही हम इस बात को Specify कर सकते हैं कि यदि DataSet Schema की Expectations पूरी न हो रही हों, तो DataAdapter को उस स्थिति में क्या करना चाहिए और इस बात को Configure करने के लिए हम DataAdapter की MissingSchemaAction Property को उपयोग में ले सकते हैं, जिसमें निम्नानुसार में से किसी एक Value को Specify किया जा सकता है:

Add Value

ये Setting इस Property की Default Setting होती है। इसे Specify करने पर यदि Current Column के लिए Schema Missing हो, तो DataAdapter स्वयं PrimaryUnique Columns Create करने के लिए Schema Information Create किए बिना अन्य Columns के लिए Schema Information Create करता है और DataSet Object में Add कर देता है।

AddWithKey Value

ये Setting, Add Setting के समान ही होती है। लेकिन इस Value को Specify करने पर DataAdapter, PrimaryUnique Keys के लिए भी Column Create करता है। जबकि ध्‍यान रखने वाली बात ये होती है कि इन Key Columns के लिए Create होने वाले Identity Column की Identity Seed Identity Increment Value Create नहीं होती। इसलिए हमें इन्हें Fill() या Update() Method को Call करने के बाद Add करना होता है।

Ignore Value

जब Current Column के लिए Schema Missing होता है, तो इस मान को Specify करने पर DataAdapter Current Column को Ignore करके अन्य Column को Analyze करने लगता है।

Error Value

जब Current Column के लिए Schema Missing होता है, तो इस मान को Specify करने पर DataAdapter एक Exception Raise करता है।

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

ADO.NET with C# in Hindi | Page:501 | Format: PDF

BUY NOW GET DEMO REVIEWS