C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[5]: ADO.NET2.0でparameterが追加できない


(過去ログ 88 を表示中)

[トピック内 6 記事 (1 - 6 表示)]  << 0 >>

■52549 / inTopicNo.1)  ADO.NET2.0でparameterが追加できない
  
□投稿者/ akira (5回)-(2010/08/14(Sat) 15:50:32)

分類:[ASP.NET (VB)] 

質問させてください。
フォーム認証のプログラムを↓このページを参考に作ってます。
http://www.atmarkit.co.jp/fdotnet/dotnettips/147aspusrdb/aspusrdb.html
AccessDBの接続をADO.NET2.0から取り入れられたFactoryパターンを使用した汎用的なコ
ードに書き直してみたのですが、2つめのParameterの追加の

param.ParameterName = "@passwd"
param.Value = FormsAuthentication.HashPasswordForStoringInConfigFile(txtPass.Text, "SHA1")
comm.Parameters.Add(param)

28行目comm.Parameters.Add(param)の行で、以下のエラーが発生し処理が止まってしまいます。
「ArgumentExceptionはユーザーコードによってハンドルされませんでした。」
「OleDbParameter は、既に別の OleDbParameterCollection に含まれています。」

Parameterの追加の書き方に間違いがあるようなのですが、どう直せば良いのか見付かりま
せんでした。アドバイス頂けると助かります。よろしくお願いします。

<%@ Page Language="VB" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.Common" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="Server">
    Sub objBtn_Click(ByVal sender As Object, ByVal e As EventArgs)
        Dim setting As ConnectionStringSettings = _
          ConfigurationManager.ConnectionStrings("MyAccessDB")
        Dim factory As DbProviderFactory = _
          DbProviderFactories.GetFactory(setting.ProviderName)
        
        Using db As DbConnection = factory.CreateConnection()
            db.ConnectionString = setting.ConnectionString
            
            ' 入力されたユーザーID、パスワードでusrテーブル内のレコードを検索
            Dim comm As DbCommand = factory.CreateCommand()
            comm.CommandText = "SELECT * FROM usr WHERE uid=@uid AND passwd=@passwd"
            comm.Connection = db

            Dim param As DbParameter = factory.CreateParameter()
            param.ParameterName = "@uid"
            param.Value = txtUsr.Text
            comm.Parameters.Add(param)
            
            param.ParameterName = "@passwd"
            param.Value = FormsAuthentication.HashPasswordForStoringInConfigFile(txtPass.Text, "SHA1")
            comm.Parameters.Add(param)

            db.Open()
            Dim reader As DbDataReader = comm.ExecuteReader()
            If reader.Read() Then
                ' 検索の結果、該当するレコードが存在した場合、認証は成功
                FormsAuthentication.RedirectFromLoginPage(txtUsr.Text, False)
            Else
                objLbl.Text = "入力したログイン情報に誤りがあります。正しい値を入力してください。"
            End If
        End Using
    End Sub
</script>

<html>
<head>
  <title>フォーム認証ログイン</title>
</head>
<body>
  <form id="Form1" runat="Server">
  <center>
    <h1>フォーム認証ログイン</h1>
      <b>ログインID:</b>
    <asp:TextBox id="txtUsr" runat="Server" Columns="12" Font-Size="Medium" 
          Width="141px" /><br />
    <b>パスワード:</b>
    <asp:TextBox id="txtPass" runat="Server" Columns="11" TextMode="Password" 
          Font-Size="Medium" Width="135px" />
    <br />
    <br />
    <asp:Button id="objBtn" runat="Server" Text="ログイン" OnClick="objBtn_Click" 
          Height="25px" Width="112px" /><br />
    <asp:Label id="objLbl" runat="Server" ForeColor="Red" />
  </center>
  </form>
</body>
</html>

開発環境:VWD2008、MS-Access2003、Windows7

引用返信 編集キー/
■52550 / inTopicNo.2)  Re[1]: ADO.NET2.0でparameterが追加できない
□投稿者/ 魔界の仮面弁士 (1749回)-(2010/08/14(Sat) 16:32:49)
No52549 (akira さん) に返信
> どう直せば良いのか見付かりませんでした。
2 つのパラメータを登録しようとしているのですから、
CreateParameter も 2 回呼び出さないといけません。

--------
提示されたコードを追ってみると:

> Dim param As DbParameter = factory.CreateParameter()
CreateParameter によって、新たなパラメータが生成されます。


> param.ParameterName = "@uid"
> param.Value = txtUsr.Text
> comm.Parameters.Add(param)
そのパラメータの名前を "@uid" にし、パラメータとして登録します。


> param.ParameterName = "@passwd"
> param.Value = FormsAuthentication.HashPasswordForStoringInConfigFile(txtPass.Text, "SHA1")
登録済みパラメータの名前を "@passwd" に変更して…

> comm.Parameters.Add(param)
それをもう一度登録しようとしています。そのため、
> 「OleDbParameter は、既に別の OleDbParameterCollection に含まれています。」
の例外が発生したのでしょう。
引用返信 編集キー/
■52552 / inTopicNo.3)  Re[2]: ADO.NET2.0でparameterが追加できない
□投稿者/ akira (6回)-(2010/08/14(Sat) 19:02:30)
No52550 (魔界の仮面弁士 さん) に返信
> ■No52549 (akira さん) に返信
>>どう直せば良いのか見付かりませんでした。
> 2 つのパラメータを登録しようとしているのですから、
> CreateParameter も 2 回呼び出さないといけません。

魔界の仮面弁士さん、早急なアドバイスありがとうございます。

param変数は使い回したいと考え、その手法ないかググッてみましたが、その手法は見つかり
ませんでした。

ググッてみたらparamとparam1の2つを使用するのが定石のようなので、その様にコードを
改造したら、希望通りの動きをする様になりました。ありがとうございました。

Dim param As DbParameter = factory.CreateParameter()
param.ParameterName = "@uid"
param.Value = txtUsr.Text
comm.Parameters.Add(param)

Dim param1 As DbParameter = factory.CreateParameter()
param1.ParameterName = "@passwd"
param1.Value = FormsAuthentication.HashPasswordForStoringInConfigFile(txtPass.Text, "SHA1")
comm.Parameters.Add(param1)


【素朴な疑問】
 ADO.NET2.0のFactoryパターンを利用した記述は、System.Data.SqlClientを利用した記述の
2倍の行数になってしまい、手間が増えたと感じますが、コードの汎用性の向上、記述のド
キュメント性が向上した事がメリットと理解すれば良いのでしょうか?

(System.Data.SqlClientを利用した場合の記述↓)
' 入力されたユーザーID、パスワードでusrテーブル内のレコードを検索
Dim objDb As New SqlConnection("Data Source=(local);User ID=sa;Password=sa;Persist Security Info=True;Initial Catalog=nettips")
Dim objCom As New SqlCommand("SELECT * FROM usr WHERE uid=@uid AND passwd=@passwd",objDb)
objCom.Parameters.Add("@uid",txtUsr.Text)
objCom.Parameters.Add("@passwd",FormsAuthentication.HashPasswordForStoringInConfigFile(txtPass.Text,"SHA1"))
objDb.Open()
Dim objDr As SqlDataReader=objCom.ExecuteReader()
If objDr.Read() Then
' 検索の結果、該当するレコードが存在した場合、認証は成功
FormsAuthentication.RedirectFromLoginPage(txtUsr.Text,False)
Else
objLbl.Text="正しいユーザーID、パスワードを入力してください"
End If
objDb.Close()
引用返信 編集キー/
■52554 / inTopicNo.4)  Re[3]: ADO.NET2.0でparameterが追加できない
□投稿者/ 魔界の仮面弁士 (1750回)-(2010/08/14(Sat) 19:34:45)
2010/08/14(Sat) 19:44:37 編集(投稿者)

No52552 (akira さん) に返信
> param変数は使い回したいと考え、その手法ないかググッてみましたが、その手法は見つかり
> ませんでした。

端折って書くなら、
 Dim p1 As DbParameter = インスタンス生成
 comm.Parameters.Add(p1)
 Dim p2 As DbParameter = インスタンス生成
 comm.Parameters.Add(p2)
という処理を、
 Dim p As DbParameter
 p = インスタンス生成
 comm.Parameters.Add(p)
 p = インスタンス生成
 comm.Parameters.Add(p)
にするだけでよいと思いますが…そういう意味ではなく?


>  ADO.NET2.0のFactoryパターンを利用した記述は、System.Data.SqlClientを利用した記述の
> 2倍の行数になってしまい、手間が増えたと感じますが、コードの汎用性の向上、記述のド
> キュメント性が向上した事がメリットと理解すれば良いのでしょうか?
SqlConnection を DbConnection で記述できるようになったというよりは
IDbConnection を DbConnection で記述できるようになったとみた方が良いかも。

1.x の IDbConnection 等を使っていた場合、インスタンスの生成時点では
SqlConnection などの固有型を呼び出さなければなりませんでしたが、
ファクトリクラスを使えば、それを改善させることができます。

すなわち、DbProviderFactory インスタンスを差し替えるだけで、
他のプロバイダーにも対応できる、という意味での汎用性はあります。
http://msdn.microsoft.com/ja-jp/library/dd278213.aspx

その一方で、SQL Server 専用アプリを作るような場合には、必ずしも
無理に System.Data.Common に拘る必要は無いと思います。
大抵は、SqlClient をそのまま使った方が便利な事も多いでしょう。

なお、今は SQL Server 専用でも、将来的に複数のプロバイダーに対応させる予定に
なっているなら、IDbConnection や DbConnection を使っておいた方が良いですが、
その場合は SQL 構文なども差し替えが利くような設計にしておかないと、
汎用化した意味が薄れてしまうかと思います。
引用返信 編集キー/
■52556 / inTopicNo.5)  Re[4]: ADO.NET2.0でparameterが追加できない
□投稿者/ akira (7回)-(2010/08/14(Sat) 22:15:20)
No52554 (魔界の仮面弁士 さん) に返信
> 2010/08/14(Sat) 19:44:37 編集(投稿者)
>
> ■No52552 (akira さん) に返信
>>param変数は使い回したいと考え、その手法ないかググッてみましたが、その手法は見つかり
>>ませんでした。
>
> 端折って書くなら、
>  Dim p1 As DbParameter = インスタンス生成
>  comm.Parameters.Add(p1)
>  Dim p2 As DbParameter = インスタンス生成
>  comm.Parameters.Add(p2)
> という処理を、
>  Dim p As DbParameter
>  p = インスタンス生成
>  comm.Parameters.Add(p)
>  p = インスタンス生成
>  comm.Parameters.Add(p)
> にするだけでよいと思いますが…そういう意味ではなく?

魔界の仮面弁士さん、↑この書き方を探していました。ズバリです。
早速↓以下の通りコードを書き直した所、

Dim param As DbParameter
param = factory.CreateParameter()
param.ParameterName = "@uid"
param.Value = txtUsr.Text
comm.Parameters.Add(param)

param = factory.CreateParameter()
param.ParameterName = "@passwd"
param.Value = FormsAuthentication.HashPasswordForStoringInConfigFile(txtPass.Text, "SHA1")
comm.Parameters.Add(param)

フォーム認証機能は希望通り動いてくれました。ありがとうございました。
解決済み
引用返信 編集キー/
■52557 / inTopicNo.6)  Re[5]: ADO.NET2.0でparameterが追加できない
□投稿者/ akira (8回)-(2010/08/14(Sat) 22:16:04)
No52554 (魔界の仮面弁士 さん) に返信
> 2010/08/14(Sat) 19:44:37 編集(投稿者)
> 
> ■No52552 (akira さん) に返信
>> ADO.NET2.0のFactoryパターンを利用した記述は、System.Data.SqlClientを利用した記述の
>>2倍の行数になってしまい、手間が増えたと感じますが、コードの汎用性の向上、記述のド
>>キュメント性が向上した事がメリットと理解すれば良いのでしょうか?
> SqlConnection を DbConnection で記述できるようになったというよりは
> IDbConnection を DbConnection で記述できるようになったとみた方が良いかも。
> 
> 1.x の IDbConnection 等を使っていた場合、インスタンスの生成時点では
> SqlConnection などの固有型を呼び出さなければなりませんでしたが、
> ファクトリクラスを使えば、それを改善させることができます。
> 
> すなわち、DbProviderFactory インスタンスを差し替えるだけで、
> 他のプロバイダーにも対応できる、という意味での汎用性はあります。
> http://msdn.microsoft.com/ja-jp/library/dd278213.aspx
> 
> その一方で、SQL Server 専用アプリを作るような場合には、必ずしも
> 無理に System.Data.Common に拘る必要は無いと思います。
> 大抵は、SqlClient をそのまま使った方が便利な事も多いでしょう。
> 
> なお、今は SQL Server 専用でも、将来的に複数のプロバイダーに対応させる予定に
> なっているなら、IDbConnection や DbConnection を使っておいた方が良いですが、
> その場合は SQL 構文なども差し替えが利くような設計にしておかないと、
> 汎用化した意味が薄れてしまうかと思います。

魔界の仮面弁士さん、疑問に対して、丁寧なわかり易い解説ありがとうございました。
ADO.NET2.0以降は、DBへの直接接続は何でもかんでもFactoryパターンを利用した記述が
推奨されるわけではないのですね。
目的、用途に合わせて、Factoryパターンで接続するか?System.Data.OleDbで接続するか?
使い分ける必要があるのですね。

早速、System.Data.OleDbで接続出来るか?やってみました。
結果、無事OleDbでも接続でき、フォーム認証が正しく機能しました。
ご指導、重ねがさねありがとうございました。

<%@ Page Language="VB" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.OleDb" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="Server">
    Sub objBtn_Click(ByVal sender As Object, ByVal e As EventArgs)
        ' 入力されたユーザーID、パスワードでusrテーブル内のレコードを検索
        Dim objdb As New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|\AccessDB.mdb")
        Dim objCom As New OleDbCommand("SELECT * FROM usr WHERE uid=@uid AND passwd=@passwd", objdb)
        objCom.Parameters.Add("@uid", OleDbType.VarChar, 50)
        objCom.Parameters("@uid").Value = txtUsr.Text
        objCom.Parameters.Add("@passwd", OleDbType.VarChar, 50)
        objCom.Parameters("@passwd").Value = FormsAuthentication.HashPasswordForStoringInConfigFile(txtPass.Text, "SHA1")
        objdb.Open()
        Dim objDr As OleDbDataReader = objCom.ExecuteReader()
        If objDr.Read() Then
            ' 検索の結果、該当するレコードが存在した場合、認証は成功
            FormsAuthentication.RedirectFromLoginPage(txtUsr.Text, False)
        Else
            objLbl.Text = "正しいユーザーID、パスワードを入力してください"
        End If
        objdb.Close()

    End Sub
</script>

<html>
<head>
  <title>フォーム認証ログイン</title>
</head>
<body>
  <form id="Form1" runat="Server">
  <center>
    <h1>フォーム認証ログイン</h1>
      <b>ログインID:</b>
    <asp:TextBox id="txtUsr" runat="Server" Columns="12" Font-Size="Medium" 
          Width="141px" /><br />
    <b>パスワード:</b>
    <asp:TextBox id="txtPass" runat="Server" Columns="11" TextMode="Password" 
          Font-Size="Medium" Width="135px" />
    <br />
    <br />
    <asp:Button id="objBtn" runat="Server" Text="ログイン" OnClick="objBtn_Click" 
          Height="25px" Width="112px" /><br />
    <asp:Label id="objLbl" runat="Server" ForeColor="Red" />
  </center>
  </form>
</body>
</html>

解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -