2010-04-01 36 views
5

Tôi đã làm việc một VBScript ADO cần chấp nhận các tham số và kết hợp các tham số đó trong chuỗi truy vấn được chuyển qua cơ sở dữ liệu. Tôi tiếp tục gặp lỗi khi Record Set Object cố gắng mở. Nếu tôi chuyển một truy vấn không có tham số, recordset sẽ mở và tôi có thể làm việc với dữ liệu. Khi tôi chạy tập lệnh thông qua trình gỡ lỗi, đối tượng lệnh không hiển thị giá trị cho đối tượng tham số. Dường như với tôi rằng tôi đang thiếu một cái gì đó liên kết đối tượng Command và đối tượng Parameter, nhưng tôi không biết những gì. Dưới đây là một chút của Mã VBScript:Làm cách nào để liên kết Tham số với các đối tượng Lệnh trong ADO bằng VBScript?

... 
'Open Text file to collect SQL query string' 
Set fso = CreateObject("Scripting.FileSystemObject") 
fileName = "C:\SQLFUN\Limits_ADO.sql" 
Set tso = fso.OpenTextFile(fileName, FORREADING) 

SQL = tso.ReadAll 

'Create ADO instance' 
connString = "DRIVER={SQL Server};SERVER=myserver;UID=MyName;PWD=notapassword; Database=favoriteDB" 
Set connection = CreateObject("ADODB.Connection") 
Set cmd = CreateObject("ADODB.Command") 

    connection.Open connString 
    cmd.ActiveConnection = connection 
    cmd.CommandText = SQL 
    cmd.CommandType = adCmdText 

    Set paramTotals = cmd.CreateParameter 
    With paramTotals 
     .value = "tot%" 
     .Name = "Param1" 
    End With 

    'The error occurs on the next line' 
    Set recordset = cmd.Execute 

    If recordset.EOF then 
     WScript.Echo "No Data Returned" 
    Else 
     Do Until recordset.EOF 
      WScript.Echo recordset.Fields.Item(0) ' & vbTab & recordset.Fields.Item(1) 
      recordset.MoveNext 
     Loop 
    End If 

Chuỗi SQL mà tôi sử dụng là khá chuẩn, ngoại trừ tôi muốn chuyển tham số cho nó. Nó giống như sau:

SELECT column1 
FROM table1 
WHERE column1 IS LIKE ? 

Tôi hiểu rằng ADO nên thay thế "?" với giá trị tham số tôi gán trong tập lệnh. Vấn đề tôi thấy là đối tượng Parameter cho thấy giá trị chính xác, nhưng trường tham số của đối tượng lệnh là null theo trình gỡ lỗi của tôi.

Trả lời

2

Tôi chưa bao giờ nhận được CreateParameter làm những gì tôi muốn. Thông số thích hợp là cần thiết để tránh SQL injection, nhưng CreateParameter là một PITA hoàn chỉnh. Rất may, có một cách thay thế: Command.Execute lấy trực tiếp tham số.

dim cmd, rs, rows_affected 
set cmd = Server.createObject("adodb.command") 
cmd.commandText = "select from Foo where id=?" 
set cmd.activeConnection = someConnection 
set rs = cmd.execute(rows_affected, Array(42)) 

Nó đẹp hơn nhiều khi được bao bọc theo cách trừu tượng phù hợp. Tôi đã viết lớp cơ sở dữ liệu của riêng mình gói ADODB.Connection vì vậy tôi sẽ không phải làm tất cả điều này theo cách thủ công. Nó phụ thuộc một chút vào lớp tùy chỉnh khác, nhưng các ý chính của nó nên được rõ ràng:

class DatabaseClass 
' A database abstraction class with a more convenient interface than 
' ADODB.Connection. Provides several simple methods to safely query a 
' database without the risk of SQL injection or the half-dozen lines of 
' boilerplate otherwise necessary to avoid it. 
' 
' Example: 
' 
' dim db, record, record_set, rows_affected 
' set db = Database("/path/to/db") 
' set record = db.get_record("select * from T where id=?;", Array(42)) 
' set record_set = db.get_records("select * from T;", empty) 
' rows_affected = db.execute("delete from T where foo=? and bar=?", 
'        Array("foo; select from T where bar=", true)) 

    private connection_ 
'  An ADODB connection object. Should never be null. 

    private sub CLASS_TERMINATE 
     connection_.close 
    end sub 

    public function init (path) 
'  Initializes a new database with an ADODB connection to the database at 
'  the specified path. Path must be a relative server path to an Access 
'  database. Returns me. 

     set connection_ = Server.createObject ("adodb.connection") 
     connection_.provider = "Microsoft.Jet.OLEDB.4.0" 
     connection_.open Server.mapPath(path) 

     set init = me 
    end function 

    public function get_record (query, args) 
'  Fetches the first record returned from the supplied query wrapped in a 
'  HeavyRecord, or nothing if there are no results. 

     dim data: set data = native_recordset(query, args) 
     if data.eof then 
      set get_record = nothing 
     else 
      set get_record = (new HeavyRecordClass).init(data) 
     end if 
    end function 

    public function get_records (query, args) 
'  Fetches all records returned from the supplied query wrapped in a 
'  RecordSet (different from the ADODB recordset; implemented below). 

     set get_records = (new RecordSetClass).init(native_recordset(query, args)) 
    end function 

    public function execute (query, args) 
'  Executes the supplied query and returns the number of rows affected. 

     dim rows_affected 
     build_command(query).execute rows_affected, args 
     execute = rows_affected 
    end function 

    private function build_command (query) 
'  Helper method to build an ADODB command from the supplied query. 

     set build_command = Server.createObject("adodb.command") 
     build_command.commandText = query 
     set build_command.activeConnection = connection_ 
    end function 

    private function native_recordset (query, args) 
'  Helper method that takes a query string and array of arguments, queries 
'  the ADODB connection, and returns an ADODB recordset containing the 
'  result. 

     set native_recordset = build_command(query).execute(, args) ' Omits out-parameter for number of rows 
    end function 
end class 
+0

Điều này phù hợp với tôi --- cảm ơn! Người đọc xin lưu ý: đối số 'Tham số' cho' .Execute' nhận một 'Biến thể'. Bạn sẽ nhận được thông báo lỗi rất mơ hồ nếu số và định dạng của thông số của bạn không khớp với những gì truy vấn mong đợi! – cxw

0

Sau khi bạn tạo các tham số, bạn phải thêm nó vào bộ sưu tập các tham số đối tượng của lệnh trước khi bạn thực hiện lệnh:

Set paramTotals = cmd.CreateParameter 
With paramTotals 
    .Value = "tot%" 
    .Name = "Param1" 
End With 

cmd.Parameters.Append paramTotals 

Bạn cũng có thể cần chỉ định các thuộc tính TypeSize cho Thông số. Nói chung, tôi sử dụng các đối số của hàm CreateParameter để thiết lập tất cả các thuộc tính cần thiết trong một dòng:

Set paramTotals = cmd.CreateParameter("Param1", adVarChar, adParamInput, 30, "tot%") 
cmd.Parameters.Append paramTotals 
6

Tôi biết điều này là cũ, nhưng đối với ai vẫn còn fiding này (như tôi đã làm qua google):

Thủ tục Nếu bạn đang sử dụng lưu trữ:

set cmd = Server.CreateObject("ADODB.Command") 
with cmd 
    .ActiveConnection = db_connection 
    .CommandText = "stored_procedure_name" 
    .CommandType = adCmdStoredProc 
    .Parameters.Append .CreateParameter("@Parameter1",adInteger,adParamInput,,1) 
     .Parameters.Append .CreateParameter("@Parameter2",adVarChar,adParamInput,100,"Up to 100 chars") 
     .Parameters.Append .CreateParameter("@Parameter3",adBoolean,adParamInput,,true) 
     .Parameters.Append .CreateParameter("@Parameter4",adDBTimeStamp,adParamInput,,now()) 
end with 
set rs = cmd.execute 
    'do stuff with returned results from select or leave blank if insert/delete/etc stored procedure 
set rs = nothing 
set cmd = nothing 

Nếu không, tôi tin rằng bạn thay đổi .CommandText để câu lệnh SQL của bạn với những câu hỏi đánh dấu tại chỗ và thông số của bạn phải tuân theo cùng một thứ tự.

Xem http://www.devguru.com/technologies/ado/quickref/command_createparameter.html Để biết chi tiết về những giá trị bạn đang chuyển với CreateParameter, cũng như danh sách các loại và mô tả của chúng.

Các vấn đề liên quan