SqlDataSource でオプティミスティック同時実行制御を実装する (VB)
このチュートリアルでは、オプティミスティック同時実行制御の要点を確認し、SqlDataSource コントロールを使用して実装する方法について説明します。
はじめに
前のチュートリアルでは、SqlDataSource コントロールに挿入、更新、削除の機能を追加する方法について説明しました。 要点としては、これらの機能を提供するには、コントロールの InsertCommand
、UpdateCommand
、または DeleteCommand
プロパティに対応する INSERT
、UPDATE
、または DELETE
のSQL ステートメントを InsertParameters
、UpdateParameters
、および DeleteParameters
コレクションの適切なパラメーターと共に指定する必要があります。 これらのプロパティとコレクションは手動で指定できますが、データ ソースの構成ウィザードの [詳細設定] ボタンには、SELECT
ステートメントに基づいてこれらのステートメントを自動的に作成する [INSERT
、UPDATE
、および DELETE
ステートメントの生成] チェック ボックスが用意されています。
[INSERT
、UPDATE
、および DELETE
ステートメントの生成] チェック ボックスに加えて、[SQL 生成の詳細オプション] ダイアログ ボックスには、[オプティミスティック同時実行制御を使用する] オプションが表示されます (図 1 を参照)。 オンにすると、自動生成された UPDATE
および DELETE
ステートメントの WHERE
句は、ユーザーが最後にデータをグリッドに読み込んだ後に基になるデータベース データが変更されていない場合にのみ、更新または削除を実行するように変更されます。
図 1: [SQL 生成の詳細オプション] ダイアログ ボックスからオプティミスティック同時実行制御のサポートを追加できます
「オプティミスティック同時実行制御の実装」に関するチュートリアルでは、オプティミスティック同時実行制御の基礎と、それを ObjectDataSource に追加する方法について説明しました。 このチュートリアルでは、オプティミスティック同時実行制御の基本について再度説明し、SqlDataSource を使用して実装する方法について説明します。
オプティミスティック同時実行制御のまとめ
複数の同時ユーザーが同じデータを編集または削除できる Web アプリケーションでは、あるユーザーが誤って別のユーザーによる変更を上書きする可能性があります。 「オプティミスティック同時実行制御の実装」チュートリアルでは、次の例を示しました。
Jisun と Sam の 2 人のユーザーが、ユーザーが GridView コントロールを使用して製品を更新および削除できるアプリケーションのページにアクセスしたとします。 ほぼ同じ時間に両者が "Chai" の編集ボタンをクリックしました。 Jisun は製品名を "Chai Tea" に変更し、[更新] ボタンをクリックします。 その結果は、データベースに送信される UPDATE
ステートメントであり、(Jisun が更新したフィールドは ProductName
の 1 つだけであっても) 製品の更新可能なフィールドがすべて設定されます。 この時点において、データベースには、この特定の製品に対して "Chai Tea" という値、"飲料" カテゴリ、"Exotic Liquids" サプライヤーなどが含まれます。 しかし、Sam の画面の GridView には、編集可能な GridView 行にまだ "Chai" という製品名が表示されています。 Jisun の変更がコミットされてから数秒後、Sam がカテゴリを "調味料" に更新し、[更新] をクリックします。 これにより、製品名を "Chai" に設定し、CategoryID
を対応する Condiments カテゴリ ID に設定する UPDATE
ステートメントがデータベースに送信されます。 製品名に対する Jisun の変更は上書きされました。
図 2 は、このやりとりを示しています。
図 2: 2 人のユーザーが同時にレコードを更新すると、1 人のユーザーの変更が他のユーザーを上書きする可能性があります (クリックすると、フルサイズの画像が表示されます)
このシナリオが起こらないようにするには、何らかのコンカレンシー制御 を実装する必要があります。 このチュートリアルの焦点であるオプティミスティック同時実行制御では、コンカレンシーの競合が随時発生する可能性がある一方で、そのような競合の大部分が発生しないという前提に基づいて機能します。 したがって、競合が発生した場合、オプティミスティック同時実行制御は、別のユーザーが同じデータを変更したため、変更を保存できないことをユーザーに通知するだけです。
Note
コンカレンシーの競合が多数あると見なされるアプリケーションや、そのような競合が許容できない場合は、代わりにペシミスティック同時実行制御を使用できます。 ペシミスティック同時実行制御の詳細については、「オプティミスティック同時実行制御の実装」チュートリアルをご覧ください。
オプティミスティック同時実行制御は、更新または削除されるレコードの値が、更新または削除プロセスの開始時と同じであることを確認することによって機能します。 たとえば、編集可能な GridView で [編集] ボタンをクリックすると、レコードの値がデータベースから読み取られ、TextBox やその他の Web コントロールに表示されます。 これらの元の値は GridView によって保存されます。 後に、ユーザーが変更を加えて [更新] ボタンをクリックした後、使用する UPDATE
ステートメントでは、元の値と新しい値を考慮し、ユーザーが編集を開始した元の値がデータベース内の値と同じ場合にのみ、基になるデータベース レコードを更新する必要があります。 図 3 は、この一連のイベントを示しています。
図 3: 更新または削除を成功させるには、元の値が現在のデータベースの値と同じでなければならない (クリックするとフルサイズの画像が表示されます)
オプティミスティック同時実行制御を実装するには、さまざまな方法があります (オプションをいくつか簡単に確認するには、Peter A. Bromberg のオプティミスティック同時実行制御の更新ロジックに関するページを参照してください)。 SqlDataSource (およびデータ アクセス層で使用される ADO.NET 型指定されたデータセット) で使用される手法により、WHERE
句が拡張され、元のすべての値の比較が含まれます。 たとえば、次の UPDATE
ステートメントは、現在のデータベース値が、GridView のレコードを更新するときに最初に取得された値と等しい場合にのみ、製品の名前と価格を更新します。 @ProductName
および @UnitPrice
パラメーターには、ユーザーが入力した新しい値が含まれます。一方、@original_ProductName
と @original_UnitPrice
には、[編集] ボタンがクリックされたときに GridView に最初に読み込まれた値が含まれます。
UPDATE Products SET
ProductName = @ProductName,
UnitPrice = @UnitPrice
WHERE
ProductID = @original_ProductID AND
ProductName = @original_ProductName AND
UnitPrice = @original_UnitPrice
このチュートリアルで説明するように、SqlDataSource でオプティミスティック同時実行制御を有効にすることは、チェック ボックスをオンにするのと同じくらい簡単です。
手順 1: オプティミスティック同時実行制御をサポートする SqlDataSource の作成
まず、SqlDataSource
フォルダーから OptimisticConcurrency.aspx
ページを開きます。 ツールボックスからデザイナーに SqlDataSource コントロールをドラッグし、その ID
プロパティを ProductsDataSourceWithOptimisticConcurrency
に設定します。 次に、コントロールのスマート タグから [データ ソースの構成] リンクをクリックします。 ウィザードの最初の画面で、NORTHWINDConnectionString
の操作を選択し、[次へ] をクリックします。
図 4: NORTHWINDConnectionString
の操作を選択します (クリックするとフルサイズの画像が表示されます)
この例では、ユーザーが Products
テーブルを編集できるようにする GridView を追加します。 そのため、図 5 に示すように、[ステートメントの選択] 画面から Products
テーブルをドロップダウン リストから選択し、ProductID
、ProductName
、UnitPrice
、Discontinued
列を選択します。
図 5: Products
テーブルから、ProductID
、ProductName
、UnitPrice
、Discontinued
列を返します (クリックするとフルサイズの画像が表示されます)
列を選択した後、[詳細設定] ボタンをクリックして、[SQL 生成の詳細オプション] ダイアログ ボックスを表示します。 [INSERT
、UPDATE
、および DELETE
ステートメントの生成] チェック ボックスと、[オプティミスティック同時実行制御を使用する] チェックボックスをオンにして、[OK] をクリックします (スクリーンショットについては、図 1 を参照してください)。 [次へ]、[完了] の順にクリックして、ウィザードを完了します。
データ ソースの構成ウィザードが完了したら、少し時間を取って、結果の DeleteCommand
プロパティと UpdateCommand
プロパティ、および DeleteParameters
コレクションと UpdateParameters
コレクションを確認します。 これを行う最も簡単な方法は、左下隅にある [ソース] タブをクリックして、ページの宣言構文を表示することです。 すると、次のような UpdateCommand
値があります。
UPDATE [Products] SET
[ProductName] = @ProductName,
[UnitPrice] = @UnitPrice,
[Discontinued] = @Discontinued
WHERE
[ProductID] = @original_ProductID AND
[ProductName] = @original_ProductName AND
[UnitPrice] = @original_UnitPrice AND
[Discontinued] = @original_Discontinued
UpdateParameters
コレクションには、次の 7 つのパラメーターがあります。
<asp:SqlDataSource ID="ProductsDataSourceWithOptimisticConcurrency"
runat="server" ...>
<DeleteParameters>
...
</DeleteParameters>
<UpdateParameters>
<asp:Parameter Name="ProductName" Type="String" />
<asp:Parameter Name="UnitPrice" Type="Decimal" />
<asp:Parameter Name="Discontinued" Type="Boolean" />
<asp:Parameter Name="original_ProductID" Type="Int32" />
<asp:Parameter Name="original_ProductName" Type="String" />
<asp:Parameter Name="original_UnitPrice" Type="Decimal" />
<asp:Parameter Name="original_Discontinued" Type="Boolean" />
</UpdateParameters>
...
</asp:SqlDataSource>
同様に、 DeleteCommand
プロパティと DeleteParameters
コレクションは次のようになります。
DELETE FROM [Products]
WHERE
[ProductID] = @original_ProductID AND
[ProductName] = @original_ProductName AND
[UnitPrice] = @original_UnitPrice AND
[Discontinued] = @original_Discontinued
<asp:SqlDataSource ID="ProductsDataSourceWithOptimisticConcurrency"
runat="server" ...>
<DeleteParameters>
<asp:Parameter Name="original_ProductID" Type="Int32" />
<asp:Parameter Name="original_ProductName" Type="String" />
<asp:Parameter Name="original_UnitPrice" Type="Decimal" />
<asp:Parameter Name="original_Discontinued" Type="Boolean" />
</DeleteParameters>
<UpdateParameters>
...
</UpdateParameters>
...
</asp:SqlDataSource>
[オプティミスティック同時実行制御の使用] オプションを選択すると、UpdateCommand
プロパティと DeleteCommand
プロパティの WHERE
句の拡張 (および各パラメーター コレクションへの追加パラメーターの追加) に加えて、他の 2 つのプロパティが調整されます。
ConflictDetection
プロパティの をOverwriteChanges
(既定値) からCompareAllValues
に変更しますOldValuesParameterFormatString
プロパティの を {0} (既定値) から original_{0} に変更します。
データ Web コントロールが SqlDataSource の Update()
または Delete()
メソッドを呼び出すと、元の値が渡されます。 SqlDataSource の ConflictDetection
プロパティが CompareAllValues
に設定されている場合、これらの元の値がコマンドに追加されます。 OldValuesParameterFormatString
プロパティは、これらの元の値パラメーターに使用される名前付けパターンを提供します。 データ ソースの構成ウィザードは、original_{0} を使用して、UpdateCommand
および DeleteCommand
プロパティの元の各パラメーター、また、UpdateParameters
および DeleteParameters
コレクションに対応する名前を付けます。
Note
SqlDataSource コントロールの挿入機能を使用していないため、 InsertCommand
プロパティとその InsertParameters
コレクションは削除して構いません。
NULL
値の正しい処理
残念ながら、オプティミスティック同時実行制御を使用する場合、データ ソースの構成ウィザードによって自動生成される拡張 UPDATE
ステートメントおよび DELETE
ステートメントは、NULL
値を含むレコードに対しては動作しません。 その理由を確認するために、SqlDataSource の UpdateCommand
を見てみましょう。
UPDATE [Products] SET
[ProductName] = @ProductName,
[UnitPrice] = @UnitPrice,
[Discontinued] = @Discontinued
WHERE
[ProductID] = @original_ProductID AND
[ProductName] = @original_ProductName AND
[UnitPrice] = @original_UnitPrice AND
[Discontinued] = @original_Discontinued
Products
テーブルの UnitPrice
列には、NULL
値が含まれる可能性があります。 もしあるレコードの UnitPrice
が NULL
値である場合、WHERE
句の [UnitPrice] = @original_UnitPrice
の部分は、NULL = NULL
は必ず False を返すことから、常に False と評価されます。 したがって、NULL
値を含むレコードは編集または削除できません。 UPDATE
ステートメントと DELETE
ステートメントの WHERE
句が更新または削除する行を一切返さないためです。
Note
このバグは、2004 年 6 月に「SqlDataSource が不適切な SQL ステートメントを生成」で Microsoft に報告され、次のバージョンの ASP.NET で修正される予定であると報告されています。
これを修正するには、NULL
値を持つ可能性のある列すべてについて、UpdateCommand
プロパティと DeleteCommand
プロパティの両方の WHERE
句を手動で更新する必要があります。 一般に、[ColumnName] = @original_ColumnName
を次に変更します。
(
([ColumnName] IS NULL AND @original_ColumnName IS NULL)
OR
([ColumnName] = @original_ColumnName)
)
この変更は、宣言型マークアップ、プロパティ ウィンドウの UpdateQuery または DeleteQuery オプション、またはデータ ソースの構成ウィザードの [カスタム SQL ステートメントまたはストアド プロシージャの指定] オプションの [UPDATE] タブと [DELETE] タブを使用して直接行うことができます。 ここでも、この変更は、UpdateCommand
または DeleteCommand
の WHERE
句に NULL
値を持つ可能性のあるすべての列に対して適用する必要があります。
これをこの例に適用すると、次の変更された UpdateCommand
と DeleteCommand
の値になります。
UPDATE [Products] SET
[ProductName] = @ProductName,
[UnitPrice] = @UnitPrice,
[Discontinued] = @Discontinued
WHERE
[ProductID] = @original_ProductID AND
[ProductName] = @original_ProductName AND
(([UnitPrice] IS NULL AND @original_UnitPrice IS NULL)
OR ([UnitPrice] = @original_UnitPrice)) AND
[Discontinued] = @original_Discontinued
DELETE FROM [Products]
WHERE
[ProductID] = @original_ProductID AND
[ProductName] = @original_ProductName AND
(([UnitPrice] IS NULL AND @original_UnitPrice IS NULL)
OR ([UnitPrice] = @original_UnitPrice)) AND
[Discontinued] = @original_Discontinued
手順 2: 編集オプションと削除オプションを持つ GridView を追加する
オプティミスティック同時実行制御をサポートするように SqlDataSource が構成されたので、残るは、このコンカレンシー コントロールを利用するページにデータ Web コントロールを追加することです。 このチュートリアルでは、編集と削除の両方の機能を提供する GridView を追加します。 これを行うには、ツールボックスからデザイナーに GridView をドラッグし、その ID
を Products
に設定します。 GridView のスマート タグから、それを手順 1 で追加した ProductsDataSourceWithOptimisticConcurrency
SqlDataSource コントロールにバインドします。 最後に、スマート タグからの [編集を有効にする] オプションと [削除を有効にする] オプションをオンにします。
図 6: GridView を SqlDataSource にバインドし、編集と削除を有効にします (クリックするとフルサイズの画像が表示されます)
GridView を追加した後に、ProductID
BoundField を削除し、ProductName
BoundField の HeaderText
プロパティを Product に変更し、HeaderText
プロパティが単に Price となるように UnitPrice
BoundField を更新して、外観を構成します。 理想的には、編集インターフェイスを拡張して、ProductName
値の RequiredFieldValidator と、UnitPrice
値の CompareValidator を含めます (適切に書式設定された数値であることを確認するため)。 GridView の編集インターフェイスのカスタマイズの詳細については、「データ変更インターフェイスのカスタマイズ」チュートリアルをご覧ください。
Note
GridView から SqlDataSource に渡された元の値はビュー状態に保存されるため、GridView のビュー状態を有効にする必要があります。
GridView に対してこれらの変更を行った後には、GridView および SqlDataSource 宣言型マークアップは次のようになります。
<asp:SqlDataSource ID="ProductsDataSourceWithOptimisticConcurrency"
runat="server" ConflictDetection="CompareAllValues"
ConnectionString="<%$ ConnectionStrings:NORTHWNDConnectionString %>"
DeleteCommand=
"DELETE FROM [Products]
WHERE [ProductID] = @original_ProductID
AND [ProductName] = @original_ProductName
AND (([UnitPrice] IS NULL AND @original_UnitPrice IS NULL)
OR ([UnitPrice] = @original_UnitPrice))
AND [Discontinued] = @original_Discontinued"
OldValuesParameterFormatString=
"original_{0}"
SelectCommand=
"SELECT [ProductID], [ProductName], [UnitPrice], [Discontinued]
FROM [Products]"
UpdateCommand=
"UPDATE [Products]
SET [ProductName] = @ProductName, [UnitPrice] = @UnitPrice,
[Discontinued] = @Discontinued
WHERE [ProductID] = @original_ProductID
AND [ProductName] = @original_ProductName
AND (([UnitPrice] IS NULL AND @original_UnitPrice IS NULL)
OR ([UnitPrice] = @original_UnitPrice))
AND [Discontinued] = @original_Discontinued">
<DeleteParameters>
<asp:Parameter Name="original_ProductID" Type="Int32" />
<asp:Parameter Name="original_ProductName" Type="String" />
<asp:Parameter Name="original_UnitPrice" Type="Decimal" />
<asp:Parameter Name="original_Discontinued" Type="Boolean" />
</DeleteParameters>
<UpdateParameters>
<asp:Parameter Name="ProductName" Type="String" />
<asp:Parameter Name="UnitPrice" Type="Decimal" />
<asp:Parameter Name="Discontinued" Type="Boolean" />
<asp:Parameter Name="original_ProductID" Type="Int32" />
<asp:Parameter Name="original_ProductName" Type="String" />
<asp:Parameter Name="original_UnitPrice" Type="Decimal" />
<asp:Parameter Name="original_Discontinued" Type="Boolean" />
</UpdateParameters>
</asp:SqlDataSource>
<asp:GridView ID="Products" runat="server"
AutoGenerateColumns="False" DataKeyNames="ProductID"
DataSourceID="ProductsDataSourceWithOptimisticConcurrency">
<Columns>
<asp:CommandField ShowDeleteButton="True" ShowEditButton="True" />
<asp:BoundField DataField="ProductName" HeaderText="Product"
SortExpression="ProductName" />
<asp:BoundField DataField="UnitPrice" HeaderText="Price"
SortExpression="UnitPrice" />
<asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued"
SortExpression="Discontinued" />
</Columns>
</asp:GridView>
オプティミスティック同時実行制御の動作を確認するには、2 つのブラウザー ウィンドウを開き、両方で OptimisticConcurrency.aspx
ページを読み込みます。 両方のブラウザーで最初の製品の [編集] ボタンをクリックします。 1 つのブラウザーで製品名を変更し、[更新] をクリックします。 ブラウザーはポストバックされ、GridView は編集前モードに戻り、編集したレコードの新しい製品名が表示されます。
2 番目のブラウザー ウィンドウで価格を変更し (ただし、製品名は元の値のままにします)、[更新] をクリックします。 ポストバックでは、グリッドは編集前モードに戻りますが、価格の変更は記録されません。 2 番目のブラウザーには、新しい製品名が古い価格の最初のブラウザーと同じ値が表示されます。 2 番目のブラウザー ウィンドウで行われた変更は失われました。 さらに、コンカレンシー違反が発生したことを示す例外やメッセージがないため、変更は暗黙のうちに失われました。
図 7: 2 番目のブラウザー ウィンドウの変更が暗黙のうちに失われました (クリックするとフルサイズの画像が表示されます)
2 つ目のブラウザーの変更がコミットされなかった理由は、UPDATE
ステートメントの WHERE
句によってすべてのレコードがフィルターで除外されたため、いずれの行にも影響を与えなかったためです。 UPDATE
ステートメントをもう一度見てみましょう。
UPDATE [Products] SET
[ProductName] = @ProductName,
[UnitPrice] = @UnitPrice,
[Discontinued] = @Discontinued
WHERE
[ProductID] = @original_ProductID AND
[ProductName] = @original_ProductName AND
(([UnitPrice] IS NULL AND @original_UnitPrice IS NULL) OR
([UnitPrice] = @original_UnitPrice)) AND
[Discontinued] = @original_Discontinued
2 番目のブラウザー ウィンドウでレコードが更新されると、WHERE
句で指定された元の製品名が既存の製品名と一致しません (最初のブラウザーによって変更されたため)。 したがって、ステートメント [ProductName] = @original_ProductName
は False を返し、UPDATE
はいずれのレコードにも影響を与えません。
Note
削除も同様に機能します。 2 つのブラウザー ウィンドウが開いた状態で、まず特定の製品を 1 つで編集し、その変更を保存します。 一方のブラウザーで変更を保存した後、もう一方のブラウザーで同じ製品の [削除] ボタンをクリックします。 DELETE
ステートメントの WHERE
句では元の値が一致しないため、削除は暗黙のうちに失敗します。
2 番目のブラウザー ウィンドウのエンド ユーザーの観点からは、[更新] ボタンをクリックすると、グリッドは編集前モードに戻りますが、変更は失われていました。 しかし、変更が反映されていないという視覚的なフィードバックはありません。 理想的には、ユーザーの変更がコンカレンシー違反のため失われた場合、それをユーザーに通知し、さらに、おそらくグリッドを編集モードに保つでしょう。 これを実現する方法を見てみましょう。
手順 3: コンカレンシー違反がいつ発生したかを判断する
コンカレンシー違反はユーザーが行った変更を拒否するので、コンカレンシー違反が発生した場合にはユーザーに警告を出すのが良いでしょう。 ユーザーに警告するには、Text
プロパティに次のメッセージが表示される ConcurrencyViolationMessage
という名前のページの上部に Label Web コントロールを追加します: "別のユーザーによって同時に更新されたレコードを更新または削除しようとしました。 他のユーザーの変更を確認してから、更新または削除をやり直してください。" Label コントロールの CssClass
プロパティを [警告] に設定します。これは、赤、斜体、太字、および大きなフォントでテキストを表示する Styles.css
で定義された CSS クラスです。 最後に、Label の Visible
プロパティと EnableViewState
プロパティを False
に設定します。 これにより、Visible
プロパティを明示的に True
に設定したポストバックのみを除き、Label は非表示になります。
図 8: Label コントロールをページに追加して警告を表示します (クリックするとフルサイズの画像が表示されます)
更新または削除を実行すると、GridView の RowUpdated
および RowDeleted
イベント ハンドラーは、要求された更新または削除をデータ ソース管理が実行した後に発生します。 これらのイベント ハンドラーから、操作の影響を受けた行の数を確認できます。 影響を受けたのが 0 行の場合は、ConcurrencyViolationMessage
ラベルを表示します。
RowUpdated
イベントと RowDeleted
イベントの両方のイベント ハンドラーを作成し、次のコードを追加します。
Protected Sub Products_RowUpdated(sender As Object, e As GridViewUpdatedEventArgs) _
Handles Products.RowUpdated
If e.AffectedRows = 0 Then
ConcurrencyViolationMessage.Visible = True
e.KeepInEditMode = True
' Rebind the data to the GridView to show the latest changes
Products.DataBind()
End If
End Sub
Protected Sub Products_RowDeleted(sender As Object, e As GridViewDeletedEventArgs) _
Handles Products.RowDeleted
If e.AffectedRows = 0 Then
ConcurrencyViolationMessage.Visible = True
End If
End Sub
どちらのイベント ハンドラーでも、e.AffectedRows
プロパティを確認し、0 の場合は、ConcurrencyViolationMessage
Label の Visible
プロパティを True
に設定します。 RowUpdated
イベント ハンドラーでは、 KeepInEditMode
プロパティを true に設定して、GridView に編集モードを維持するように指示します。 その際、他のユーザーのデータが編集インターフェイスに読み込まれるように、データをグリッドに再バインドする必要があります。 これを行うには、GridView の DataBind()
メソッドを呼び出します。
図 9 に示すように、これら 2 つのイベント ハンドラーでは、コンカレンシー違反が発生するたびに非常に顕著なメッセージが表示されます。
図 9: コンカレンシー違反が発生した場合にメッセージが表示される (クリックするとフルサイズの画像が表示されます)
まとめ
複数の同時ユーザーが同じデータを編集している可能性がある Web アプリケーションを作成する場合は、コンカレンシー制御オプションを検討することが重要です。 既定では、ASP.NET データ Web コントロールとデータ ソース コントロールはコンカレンシー制御を使用しません。 このチュートリアルで説明したように、SqlDataSource を使用したオプティミスティック同時実行制御の実装は比較的迅速かつ簡単です。 SqlDataSource は、自動生成された UPDATE
および DELETE
ステートメントに拡張 WHERE
句を追加するためのほとんどの作業を処理しますが、「NULL
値の正しい処理」セクションで説明されているように、NULL
値列の処理にはいくつかの微妙な点があります。
このチュートリアルで、SqlDataSource の検討は終了です。 残りのチュートリアルでは、ObjectDataSource と階層化アーキテクチャを使用したデータの操作に戻ります。
プログラミングに満足!
著者について
7 冊の ASP/ASP.NET 書籍の著者であり、4GuysFromRolla.com の創設者である Scott Mitchell は、1998 年から Microsoft Web テクノロジに取り組んでいます。 Scott は、独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の本は サムズは24時間で2.0 ASP.NET 自分自身を教えています。 にアクセスするか、ブログを使用して にアクセスmitchell@4GuysFromRolla.comできます。これは でhttp://ScottOnWriting.NET見つけることができます。