Record Updating in ASP.NET Project

Record Updating in ASP.NET – अभी तक हमने SqlDataSource Control का प्रयोग करते हुए Underlying Database से Required Records को Retrieve किया है और उन्हें ListBox, DropDownList, GridView, DetailsView जैसे Controls के माध्‍यम से Output में Render किया है।

लेकिन SqlDataSource Control द्वारा हम जिन Records को Retrieve करते हैं, उनमें किए गए Changes को Underlying Database में Update भी कर सकते हैं। लेकिन सभी Binding Controls Updating को Support नहीं करते।

उदाहरण के लिए ListBox Control हमें कोई ऐसा तरीका Provide नहीं करता, जिनका प्रयोग करके हम Underlying Database से आने वाले Records के Data को Edit करके Permanently Save कर सकें अथवा किसी नए Record को Underlying Database में Insert कर सकें।

लेकिन ASP.NET Framework हमें GridView, DetailsView FormView जैसे Rich Data Controls भी Provide करता है, जिनका प्रयोग करते हुए हम किसी Record को जरूरत के अनुसार Edit भी कर सकते हैं और ऐसा करने के लिए हमें केवल इन Controls के लिए इन Editing Feature को Enable मात्र ही करना होता है।

यानी जब हम इन Rich Controls को Use करते हैं, तब हम इस बात को तय कर सकते हैं कि उन Controls में दिखाई देने वाले Records को User केवल Edit ही कर सकता है या वह नए Records Insert भी कर सकता है तथा किसी Record को Delete भी कर सकता है।

यानी एक User किसी Rich Control में दिखाई देने वाले Records के साथ क्या&क्या Actions Perform कर सकता है, इस बात को हम उस Control के साथ उपलब्ध Enable/Disable Features का प्रयोग करते हुए तय कर सकते हैं।

जिस तरह से हमने पिछले Examples में Parameterized Query या Stored Procedure के माध्‍यम से अपने SqlDataSource Control के लिए SelectCommand को Define किया था, ठीक उसी तरह से हम InsertCommand, UpdateCommand DeleteCommand को भी Define कर सकते हैं।

उदाहरण के लिए मानलो कि हम अपने Webpage पर दिखाई देने वाले विभिन्न Products की Information को Webpage पर ही Edit करने की सुविधा देना चाहते हैं। इस जरूरत को पूरा करने के लिए हम एक नया SqlDataSource Control Create कर सकते हैं और इसकी विभिन्न जरूरी Properties को निम्नानुसार Set कर सकते हैं:

PropertyValue
IDsourceProducts
ConnectionStringNorthwind

(Data Source=.;Initial Catalog=Northwind;Integrated Security=True)

SelectCommandTypeText
SelectQuerySELECT * FROM Products

उस SqlDataSource Control की उपरोक्तानुसार विभिन्न जरूरी Properties को Set करने के बाद हमें हमारे Page पर एक GridView Control Place करना होता है और उसके लिए सबसे पहले निम्न चित्रानुसार “Choose Data Source:” Combobox से sourceProducts को Select करना होता है:

Record Updating in ASP.NET Project - ITeBooks in Hindi

Record Updating in ASP.NET Project – ITeBooks in Hindi

Choose Data Source:” Combobox से sourceProducts को Select करते ही इस Popup में निम्न चित्रानुसार कुछ और Hyperlinks Add हो जाते हैं:

Record Updating in ASP.NET Project - ITeBooks in Hindi

Record Updating in ASP.NET Project – ITeBooks in Hindi

इस Popup में दिखाई देने वाले “Refresh Schema” Hyperlink को Click करते ही हमारा GridView Control निम्न चित्रानुसार Underlying Recordset के अनुसार Update हो जाता है:

Record Updating in ASP.NET Project - ITeBooks in Hindi

Record Updating in ASP.NET Project – ITeBooks in Hindi

हालांकि यदि हम अभी हमारे इस Webpage को Run करें, तो हमें हमारे सभी Products की List एक GridView के रूप में निम्न चित्रानुसार दिखाई देने लगता है:

Record Updating in ASP.NET Project - ITeBooks in Hindi

Record Updating in ASP.NET Project – ITeBooks in Hindi

लेकिन यदि हम इस दिखाई देने वाले Products की List में किसी Product की Information को Edit नहीं कर सकते। लेकिन क्‍योंकि हम हमारे Products को Rendered Mode में Edit करना चाहते हैं, इसलिए हमें हमारे SqlDataSource Control के UpdateCommand को भी Configure करना होगा, जिसके लिए UpdateCommandType तथा UpdateQuery Property को निम्नानुसार Set करना होता है:

PropertyValue
InsertCommandTypeText
InsertQueryUPDATE Products SET
   ProductName = @ProductName,
   SupplierID = @SupplierID,
   CategoryID = @CategoryID,
   QuantityPerUnit = @QuantityPerUnit,
   UnitPrice = @UnitPrice,
   UnitsInStock = @UnitsInStock,
   UnitsOnOrder = @UnitsOnOrder,
   ReorderLevel = @ReorderLevel,
   Discontinued = @Discontinued
WHERE ProductID = @ProductID

जब हम हमारे SqlDataSource Control के लिए Ellipsis Button पर Click करने पर Display होने वाले Command and Parameter Editor Window द्वारा उपरोक्तानुसार InsertQuery को निम्नानुसार Specify कर देते हैं:

Record Updating in ASP.NET Project - ITeBooks in Hindi

Record Updating in ASP.NET Project – ITeBooks in Hindi

उसके बाद जब हम हमारे Visual Studio के Design View में SqlDataSource Control को Select करते हैं, तो Display होने वाले Popup में निम्न चित्रानुसार “Enable Editing” नाम का एक और Hyperlink Add हो जाता है:

Record Updating in ASP.NET Project - ITeBooks in Hindi

Record Updating in ASP.NET Project – ITeBooks in Hindi

इस “Enable Editing” Hyperlink को Check करते ही हमारे GridView Control की शु:आत में निम्न चित्रानुसार Edit नाम का एक Hyperlink दिखाई देने लगता है:

Record Updating in ASP.NET Project - ITeBooks in Hindi

Record Updating in ASP.NET Project – ITeBooks in Hindi

इसलिए जब इस बार हम हमारे इस Webpage को Run करते हैं, तो हमें निम्नानुसार Output प्राप्त होता है:

Record Updating in ASP.NET Project - ITeBooks in Hindi

Record Updating in ASP.NET Project – ITeBooks in Hindi

जहां यदि हम पहले Product के “Edit” Hyperlink को Click करें, तो वह Record Editing के लिए निम्न चित्रानुसार दिखाई देने लगता है:

Record Updating in ASP.NET Project - ITeBooks in Hindi

Record Updating in ASP.NET Project – ITeBooks in Hindi

Record की Editing करने के बाद हम “Update” Hyperlink को Click करके किए गए Change को Underlying Database में Permanently Save कर सकते हैं, अथवा “Cancel” Hyperlink को Click करके Changes को Update होने से रोक सकते हैं।

हम देख सकते हैं कि इस उदाहरण में हमने अपने Record की Editing करने के लिए कोई Custom Program Logic Create नहीं किया है, बल्कि अपने SqlDataSource Control के लिए केवल UpdateCommandType को “Text” Value से तथा UpdateQuery Property को एक UPDATE SQL Query से Set किया है, जबकि वह Query पूरी तरह से एक Parameterized SQL Query है, जिसके Primary Key Column को WHERE Clause के बाद Specify किया है।

जब हम UPDATE Query को इस तरह से Specify करते हैं, जिस तरह से उपरोक्त Example में किया है, तो ASP.NET स्वयं ही अपने स्तर पर समझ जाता है कि उसे किस Parameter को किस Underlying Table Column से Associate करना है। परिणामस्वरूप जब हम किसी Record को Edit करके Update करते हैं, तो केवल वही Record Edit होकर Update होता है, जिसे Edit किया गया है।

यहां ये बात ध्‍यान रखना जरूरी है कि हमारा GridView Control उसी स्थिति में हमें “Enable Editing” Checkbox Provide करता है, जबकि उसकी AutoGenerateEditButton Property में “True” Set हो। लेकिन इस Property को केवल उसी स्थिति में True Set करना चाहिए, जबकि UpdateQuery Property को Appropriate SQL UPDATE Statement से Set किया गया हो, अन्‍यथा Exception Trigger होता है।

ठीक इसी तरह से हम AutoGenerateSelectButtonAutoGenerateDeleteButton Property को भी True Set कर सकते हैं, लेकिन उस स्थिति में क्रमश: SelectQuery DeleteQuery को Appropriate SELECT या DELETE SQL Statement से Set किया गया होना जरूरी होता है अन्‍यथा Runtime में जब इनसे Associated Select या Delete Hyperlinks को Click किया जाता है, तो Runtime Exception Generate होता है।

एक बार फिर हम देख सकते हैं कि अपने Record में किए गए Changes को Underlying Database में Update करने के लिए हमने एक UPDATE SQL Query के अलावा और कुछ भी नहीं लिखा है, क्‍योंकि GridView जैसे Rich Data Control को Use करने पर सभी जरूरी Updating Operations ASP.NET Framework स्वयं Internally करता है और हमारे लिए जरूरी Markups भी निम्नानुसार स्वयं ही Generate करता है:

File Name: DataUpdating.asxp

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="DataUpdating.aspx.cs" Inherits="DataUpdate.DataUpdating" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
   
        <asp:SqlDataSource
         ID="sourceProducts" runat="server"
         ConnectionString="<%$ ConnectionStrings:Northwind %>"
         SelectCommand="SELECT * FROM Products"
         UpdateCommand="UPDATE Products SET
            ProductName = @ProductName,
            SupplierID = @SupplierID,
            CategoryID = @CategoryID,
            QuantityPerUnit = @QuantityPerUnit,
            UnitPrice = @UnitPrice,
            UnitsInStock = @UnitsInStock,
            UnitsOnOrder = @UnitsOnOrder,
            ReorderLevel = @ReorderLevel,
            Discontinued = @Discontinued
            WHERE ProductID = @ProductID"
        ></asp:SqlDataSource>
        <br />
        <asp:GridView ID="GridView1" runat="server" DataSourceID="sourceProducts">
            <Columns>
                <asp:CommandField ShowEditButton="True" />
            </Columns>
        </asp:GridView>
  
    </div>
    </form>
</body>
</html>

इस Example में हमने ProductID के आधार पर Match करते हुए Record को Update किया है। लेकिन इस Approach के साथ एक समस्या ये है कि जब UPDATE Command Execute होता है, तो वह Record के सभी Fields को Update करता है, फिर भले ही हमने केवल ProductName Field के मान को ही Change क्‍यों न किया हो।

परिणामस्वरूप यदि एक ही Page को लगभग समान समय पर दो अलग Users ने Request किया हो और दोनों ही Users उस समान Record के अलग-अलग Fields के Data को Change कर रहे हों, तो उस स्थिति में जो User बाद में अपने Record के Data को Save करेगा, उसके Record के Fields पिछले User द्वारा Save किए गए Record के Fields को भी Overwrite कर देगा, भले ही दूसरे User ने उन Fields के मानों में कोई परिवर्तन न किया हो, जिन्हें पहले User ने Modify किया है।

क्‍योंकि दोनों ही Users को Request के समय जो Record प्राप्त हुए थे, उनके सभी Fields के Data दोनों Users के लिए समान थे। लेकिन जब पहले User ने Record के किसी Field के Data को Change किया] तो वह Change दूसरे User के Record पर Reflect नहीं हुआ] क्‍योंकि दोनों ही Users ने लगभग समान समय पर Request Perform किया था और Record के साथ दोनों ही Users का कोई Direct Connection नहीं है।

इसलिए एक User द्वारा किए गए Changes की जानकारी दूसरे User को तब तक नहीं हो सकती, जब तक कि वह दूसरा User अपने Record को Update करने से पहले एक बार फिर से उसी Record का Request Perform न करे, क्‍योंकि दोनों ही Users समान Record को एक Stateless Protocol के माध्‍यम से Retrieve कर रहे हैं और पहले User द्वारा किए गए Changes की जानकारी दूसरे User को किसी भी स्थिति में Directly प्राप्त नहीं हो सकती।

इस समस्या से बचने के लिए हम Concurrency Checking को Enforce कर सकते हैं और Concurrency Checking को Enforce करने का एक तरीका ये है कि हम ऐसा Command Create करें, जो केवल उसी स्थिति में Update Perform करे, जबकि उस Record के सभी Fields के मान अपने पिछले मान से Exactly Match हों और इस तरह की UPDATE SQL Query को हम निम्नानुसार Specify कर सकते हैं:

UPDATE Products
SET
ProductName = @ProductName,
SupplierID = @SupplierID,
CategoryID = @CategoryID,
QuantityPerUnit = @QuantityPerUnit,
UnitPrice = @UnitPrice,
UnitsInStock = @UnitsInStock,
UnitsOnOrder = @UnitsOnOrder,
ReorderLevel = @ReorderLevel,
Discontinued = @Discontinued

      WHERE

            ProductID = @original_ProductID AND
            ProductName = @original_ProductName AND
            SupplierID = @original_SupplierID AND
            CategoryID = @original_CategoryID AND
            QuantityPerUnit = @original_QuantityPerUnit AND
            UnitPrice = @original_UnitPrice AND
            UnitsInStock = @original_UnitsInStock AND
            UnitsOnOrder = @original_UnitsOnOrder AND
            ReorderLevel = @original_ReorderLevel AND
            Discontinued = @original_Discontinued

इस SQL Command में हमने एक महत्वपूर्ण Change किया है, जहां WHERE Clause @ProductName, @SupplierID, आदि Parameters को Match करने की कोशिश नहीं करता, क्‍योंकि ये Parameters, Current Values को Reflect करते हैं, जो कि हो सकता है कि उन Original Values से Match न हों, जो कि Request Perform करते समय Retrieve हुई थीं] बल्कि इन Parameter को हमने @original_FieldName तरीके से Specify किया है।

अब Simple सा सवाल ये पैदा होता है कि ये @original_FieldName Parameters में Values कहां से आ रहे हैं?

इन Parameters की Original Values को Access करने के लिए SqlDataSource को ये बताना होता है कि हम Record को Update करने से पहले उस Record की Original Values को Access करना चाहते हैं और ऐसा करने के लिए हमें SqlDataSource Control की ConflictDetection Property को ConflictOptions.CompareAllValues मान से Set करना होता है, जबकि इसका Default मान ConflictOption.OverwriteChanges होता है।

साथ ही हमें SqlDataSource Control को ये भी बताना होता है कि Original Values को Hold करने वाले Parameters का नाम किस प्रकार से तय करना है। क्‍योंकि Default रूप से सभी Original Values वाले Parameters का नाम वही होता है, जो नाम Changes Values वाले Parameters का होता है और समान नाम होने की वजह से वास्तव में Changed Values वाले Parameter Names, Original Values वाले Parameters को Overwrite करते हैं।

SqlDataSource Control के इस Behavior को Prevent करने के लिए हमें SqlDataSource.OldValuesParameterFormatString Property को Set करना होता है। जहां ये Property एक String Parameter Accept करता है, जिसमें एक {0} Placeholder होता है। ये {0} Placeholder ही Original Parameter Name को Represent करता है।

उदाहरण के लिए यदि हम OldValuesParameterFormatString Property में “original_{0}” String को Set करते हैं, जो प्रत्‍येक Original Parameter के लिए “original_” एक Prefix की तरह Append हो जाता है। इस तरह से @ProductID Parameter वास्तव में @original_ProductID Parameter की तरह Represent होने लगता है।

इस तरह से अब यदि हम हमारे SqlDataSource Control की इन दोनों Properties को Set करें, तो हमें Concurrency की वजह से पैदा होने वाली समस्या का सामना नहीं करना पडेगा। जबकि उपरोक्तानुसार तरीके से ConflictDetection, OldValuesParameterFormatString UpdateQuery Properties को Modify करें, तो Visual Studio हमारे लिए जो Markups Generate करता है, वे निम्नानुसार होते हैं:

File Name: DataUpdating.asxp

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="DataUpdating.aspx.cs" Inherits="DataUpdate.DataUpdating" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
   
        <asp:SqlDataSource
         ID="sourceProducts" runat="server"
         ConnectionString="<%$ ConnectionStrings:Northwind %>"
         SelectCommand="SELECT * FROM Products"
         UpdateCommand=" UPDATE Products
      SET
            ProductName = @ProductName,
            SupplierID = @SupplierID,
            CategoryID = @CategoryID,
            QuantityPerUnit = @QuantityPerUnit,
            UnitPrice = @UnitPrice,
            UnitsInStock = @UnitsInStock,
            UnitsOnOrder = @UnitsOnOrder,
            ReorderLevel = @ReorderLevel,
            Discontinued = @Discontinued
      WHERE
            ProductID = @original_ProductID AND
            ProductName = @original_ProductName AND
            SupplierID = @original_SupplierID AND
            CategoryID = @original_CategoryID AND
            QuantityPerUnit = @original_QuantityPerUnit AND
            UnitPrice = @original_UnitPrice AND
            UnitsInStock = @original_UnitsInStock AND
            UnitsOnOrder = @original_UnitsOnOrder AND
            ReorderLevel = @original_ReorderLevel AND
            Discontinued = @original_Discontinued"
      ConflictDetection="CompareAllValues"
      OldValuesParameterFormatString="original_{0}"
   ></asp:SqlDataSource>
        <br />
        <asp:GridView ID="GridView1" runat="server" DataSourceID="sourceProducts">
            <Columns>
                <asp:CommandField ShowEditButton="True" />
            </Columns>
        </asp:GridView>
  
    </div>
    </form>
</body>
</html>

जब हम इस Approach को Use करते हुए Update Operation Perform करते हैं, तब Concurrency की समस्या तो Solve हो जाती है, लेकिन क्‍योंकि इस Approach में हमें प्रत्‍येक Field को Original Values से Compare करना जरूरी होता है, इसलिए काफी ज्यादा Data Network के बीच Flow होता है तथा Underlying Database को भी काफी ज्यादा Comparision करना पडता है।

अत: एक ज्यादा बेहतर Solution के रूप में हम Timestamp Field को Use कर सकते हैं, जो कि हमारे Bound Data Control के अन्तर्गत एक Hidden Filed की तरह Exist रहता है। परिणामस्वरूप यदि इस Field का Data Unchanged हो, तो ये इसी बात का Indication है कि Record में किसी भी अन्‍य User द्वारा कोई Update नहीं किया गया है। इसलिए बिना कोई Comparision किए हुए भी हम Directly अपने Changes को Underlying Database पर Apply कर सकते हैं।

इस Approach के अलावा एक और Approach Use किया जा सकता है, जिसके अन्तर्गत हम Bound Control के DataKeyNames Property को Set करते हुए Parameters की Original Values को Access कर सकते हैं।

उदाहरण के लिए यदि हम GridView.DataKeyNames Property में ProductID को Value के रूप में Set कर दें, तो हम हमारे Update किए जाने वाले Record की Original Values व Current Values दोनों को Access करने में सक्षम हो जाते हैं, यद्धपि हमें इस Property को Set करने के बावजूद OldValuesParameterFormatString Property को Appropriate Value से Set करना जरूरी होता है।

हालांकि DataKeyNames Property में हम जिस Field को Set करते हैं, उसका एक Primary Key होना जरूरी होता है और सामान्‍यत: इसी Key Field का प्रयोग करते हुए किसी Record को Uniquely Identify किया जाता है।

साथ ही यदि हम Concurrency Checking के उद्देश्‍य से Update किए जाने वाले Record की Original Values का भी Track रखना चाहते हैं, तो हमें हमेंशा ConflictDetection Property को Use करना जरूरी होता है।

Parameterized Command in ASP.NET
Record Inserting in ASP.NET Project

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

Advance ASP.NET WebForms in Hindi | Page:707 | Format: PDF

BUY NOW DOWNLOAD READ ONLINE

Download All EBooks

सभी हिन्दी EBooks के DEMO DOWNLOAD LINKS प्राप्‍त करें, अपने EMail पर।

Register करके Login करें। इस Popup से छुटकारा पाएें।