http://blogs.sqlpassj.org/masatotaniguchi/archive/2005/06/10/9475.aspx
のASP版(非ASP.NET)です。ActiveX dllを使用し、ASPファイルからデータアクセス部分を分離、少ない変更で複数のデータベースに対応できるようにします。
Visual Basic 6.0で、ActiveX dllを作成し、ScottDAOという名前をつけます。これは、以前にご紹介したVB6版をActiveX dll化したものです。
※以下のソースコードはエラー処理などが省略してあり、完全ではありません。
テーブル(OracleのScott.Empテーブルと、それをSQL Server 2000にインポートしたテーブル)のレコードを保存するために、VO(Value Object)を用意します。これはVB6版と全く同じでそのまま移植できます。
Instancingプロパティは5-MultiUseとします。
' ソースコード(clsEmpVo):クラスモジュール
' Private 変数
' 従業員番号
Private m_lngEmpNo As Long
' 従業員名
Private m_strEname As String
' 以下略
' プロパティ
Public Property Get EMPNO() As Long
EMPNO = m_lngEmpNo
End Property
Public Property Let EMPNO(lngEmpNo As Long)
m_lngEmpNo = lngEmpNo
End Property
Public Property Get Ename() As String
Ename = m_strEname
End Property
Public Property Let Ename(strEname As String)
m_strEname = strEname
End Property
' 以下略(フィールド分同じものを作ります)
インターフェースクラスは外部に公開したいため、Instancingプロパティを5-MultiUseとします。
これをこのまま公開しても、中は空っぽです。後でちょっと細工をします。
' ソースコード(clsEmpDao) :クラスモジュール
Public Function SelectEmp(lngDeptNo As Long) As Collection
End Function
Public Function InsertEmp(EmpVo As clsEmpVo) As Boolean
End Function
Public Function UpdateEmp(EmpVo As clsEmpVo) As Boolean
End Function
Public Property Set Connection(con As Object)
End Property
clsEmpSQLServerDaoはVB6版とほとんど同じです(選択条件が部署番号になっている部分だけが違います)。このクラスは外部に公開しないため、Instancingプロパティを1-Privateとします。
Oracleについても全く同じなので、ここでは省略します。VB6版をご参照ください。
なお、nvl関数は標準モジュールにある独自の関数で動作はORACLEのNVLと全く同じです。
' ソースコード(clsEmpSQLServerDao):クラスモジュール
Implements clsEmpDao
Private Connection As Object
Public Property Set clsEmpDao_Connection(con As Object)
Set Connection = con
End Property
Public Function clsEmpDao_SelectEmp(lngDeptNo As Long) As Collection
Dim cmd As New ADODB.Command
Dim result As New Collection
Dim rs As ADODB.Recordset
' Commandの設定
With cmd
.ActiveConnection = Connection
.CommandText = "SELECT * FROM EMP WHERE DEPTNO = ?"
.CreateParameter , adInteger, adParamInput
.Parameters(0).Value = lngDeptNo
End With
' SQLを実行して結果セットを取得します
Set rs = cmd.Execute
' Recordsetから、VOへ値を詰めます
Do Until rs.EOF
Dim EmpVo As clsEmpVo
Set EmpVo = New clsEmpVo
EmpVo.EmpNo = nvl(rs.Fields("EMPNO"), 0)
EmpVo.Ename = nvl(rs.Fields("ENAME"), "")
EmpVo.Job = nvl(rs.Fields("JOB"), "")
EmpVo.Mgr = nvl(rs.Fields("MGR"), 0)
EmpVo.HireDate = nvl(rs.Fields("HireDate"), 0)
EmpVo.Sal = nvl(rs.Fields("SAL"), 0)
EmpVo.Comm = nvl(rs.Fields("COMM"), 0)
EmpVo.DeptNo = nvl(rs.Fields("DEPTNO"), 0)
Call result.Add(EmpVo)
rs.MoveNext
Loop
' 後始末
rs.Close
Set rs = Nothing
' 戻り値(VOのコレクション)の設定
Set clsEmpDao_SelectEmp = result
End Function
Public Function clsEmpDao_InsertEmp(EmpVo As clsEmpVo) As Boolean
' 省略
End Function
Public Function clsEmpDao_UpdateEmp(EmpVo As clsEmpVo) As Boolean
' 省略
End Function
さて、公開したいのはEmpDaoですがASPに渡したいのは中身の詰まったクラスです。
そこで以下のようなクラスを作成し外部に公開します(Instancingプロパティを5-MultiUse)。
データベースを変更する必要が出た時はここを変更します。
' ソースコード(clsScottDaoFactory):クラスモジュール
' このクラスが生成するDAOは、clsScottDaoFactory
' のインスタンスが存命中の場合のみ使用できます。
' clsScottDaoFactoryインスタンスの消滅とともにDB
' 接続も自動的にCloseされるためです。
Private Connection As clsConnection
Public Function EmpDAO() As clsEmpDao
Dim emp As clsEmpDao
' DB変更時、コードの変更が必要な場所
Set emp = New clsEmpSQLServerDao
' Set emp = New clsEmpOracleDao
Set Emp.Connection = Connection.GetConnection
Set EmpDAO = emp
End Function
Private Sub Class_Initialize()
Dim ConnectionFactory As New clsConnectionFactory
Set Connection = ConnectionFactory.GetClsConnection
End Sub
' このメソッドは使用後、なるべく早く実行するようにします。
Public Sub CloseConnection()
Connection.CloseConnection
Set Connection = Nothing
End Sub
' 安全策
Private Sub Class_Terminate()
If Not Connection Is Nothing Then
Connection.CloseConnection
End If
End Sub
DBの接続のためのクラス、clsConnectionを定義します。これはインターフェースとして扱います(Instancingプロパティを5-MultiUse)。
' ソースコード(clsConnection):クラスモジュール
Public Function GetConnection() As Object
End Function
Public Sub CloseConnection()
End Sub
SQLServerのためのclsConnectionの実装クラスを定義します(Instancingプロパティを1-Private)。Oracle用のclsOracleConnectionは省略します。
' ソースコード(clsSQLServerConnection):クラスモジュール
Implements clsConnection
Private adoSQLServerCon As ADODB.Connection
Public Function clsConnection_GetConnection() As Object
Set clsConnection_GetConnection = adoSQLServerCon
End Function
Public Sub clsConnection_CloseConnection()
adoSQLServerCon.Close
Set adoSQLServerCon = Nothing
End Sub
Private Sub Class_Initialize()
Set adoSQLServerCon = New ADODB.Connection
adoSQLServerCon.ConnectionString = _
"PROVIDER=SQLOLEDB;SERVER=ServerName;DATABASE=Scott;UID=sa;PWD=*******"
adoSQLServerCon.Open
End Sub
clsConnectionクラスを作成するためのクラスを定義します(
Instancingプロパティを5-MultiUse)。
' ソースコード(clsConnectionFactory):クラスモジュール
Public Function GetClsConnection() As clsConnection
' DB変更時、コードの変更が必要な場所
Set GetClsConnection = New clsSQLServerConnection
' Set GetClsConnection = New clsOracleConnection
End Function
以上のActiveX dllを作成しレジストリに登録します。これをテストするためのASPファイルを用意しました。
For Eachが不安な方は、レコード数をresult.countで取得できるのでFor...Next文で書き換えてもいいと思います。
' ソースコード(ScottEmp.asp):aspファイル
<HTML>
<BODY>
<%
Set scottDAOFactory = Server.CreateObject("ScottDAO.clsScottDAOFactory")
Set empDAO = scottDAOFactory.EmpDAO
Set result = empDAO.SelectEmp(20)
scottDAOFactory.CloseConnection
%>
<TABLE border="1">
<TR>
<TH>従業員番号</TH>
<TH>名前</TH>
<TH>職種</TH>
<TH>上司</TH>
<TH>入社日</TH>
<TH>給料</TH>
<TH>歩合</TH>
<TH>部署番号</TH>
</TR>
<%
For Each empVo In result
%>
<TR>
<TD><%=empVo.EmpNo%></TD>
<TD><%=empVo.Ename%></TD>
<TD><%=empVo.Job%></TD>
<TD><%=EmpVo.Mgr%></TD>
<TD><%=EmpVo.Hiredate%></TD>
<TD><%=empVo.Sal%></TD>
<TD><%=EmpVo.Comm%></TD>
<TD><%=empVo.deptNo%></TD>
</TR>
<%
Next
%>
</TABLE>
</BODY>
</HTML>
基本方針は、
aspファイルには画面表示ロジック以外はなるべく書かないようにする
ということです。ビジネスロジックもActiveX dllでカプセル化し、aspファイルからはそれを呼ぶだけにするようにします。