I have 3 pages:
my DB-class
<!--#include virtual="/res/adovbs.inc"-->
<%
Class classDB
'Declarations
Private SQL
Private RS
Private Conn
'Class Initialization
Private Sub Class_Initialize()
Set Conn = Server.CreateObject("ADODB.Connection")
Conn.ConnectionString = "DSN=x"
Call Conn.Open
End Sub
'Terminate Class
Private Sub Class_Terminate()
If IsObject(RS) Then
If RS.State = 1 Then
RS.Close()
End If
End If
If Conn.State = 1 Then
Conn.Close()
End If
End Sub
Public Function GetRS(SQL)
Set RS = Conn.Execute(SQL)
GetRS = RS
End Function
Public Function ExecuteSQL(SQL)
Conn.Execute(SQL)
End Function
End Class
%>
And my "functions":
<!--#include virtual="/res/classDB.asp"-->
<%
'GET PAGED MEMBERS
Function GetMembers(page)
If Not IsNumeric(page) Or page = "" Then page = 1
Dim db : Set db = new classDB
Set GetMembers = db.GetRS("SELECT * FROM member")
End Function
.....
And in my page:
<%
Dim members : Set members = GetMembers(1)
If Not members.EOF Then
Do Until members.EOF
%>
I get Error:
The object does not support the property or method 'EOF'
What might be wrong here? An Object was returned to the page. But I guess it has no properties or entries.... Impossible to debug.
EDIT:
Function GetMembers(page)
If Not IsNumeric(page) Or page = "" Then page = 1
Dim rs
Dim m : Set m = new classDB
Set rs = m.GetRS("SELECT * FROM member")
Response.Write(rs("email"))
Set GetMembers = rs
End Function
It prints out the email for the "member".... but it doesn't work on the "next" page with the loop.
It's it returning the recordset to the page?
<%
Dim m : Set m = GetMembers(1)
If Not m.EOF Then
Do Until m.EOF
%>
Is not working..... what to do?
EDIT
I changed to:
Public Function GetRS(SQL)
Dim RS : Set RS = m_Conn.Execute(SQL)
Set GetRS = RS
End Function
Now I get error:
"The action is not allowed when the object is closed"
Google translated :)
I have the open in the Class_Initialize.... why?
The first error is due to the lack of Set on the returned object reference in the GetRS() method in the classDB class. The fix for this is to change the return value so it is prefixed with Set like this;
Public Function GetRS(SQL)
Dim RS: Set RS = Conn.Execute(SQL)
'Returning object references from a function requires the "Set" statement.
Set GetRS = RS
End Function
You then reported a "not allowed when closed" error. This comes from the encapsulation of the ADODB.Connection object inside the classDB object instance. Because the connection is scoped to the class returning a recordset causes the connection to be severed, hence the recordset returning as closed.
The fix is to bring the connection outside the class so it lives in the context of the page and then passes it into the class via a parameter. There are varying ways of doing this, you could add a argument to the GetRS() method but this would only affect that single method. The other option is to build a sub procedure that you call after instantiation of the class to set the connection, something like;
Class classDB
'Declarations
Private SQL
Private RS
Private Conn
Public Sub Init(conn)
Set Conn = conn
End Sub
'Terminate Class
Private Sub Class_Terminate()
If IsObject(RS) Then
If RS.State = 1 Then
RS.Close()
End If
End If
If Conn.State = 1 Then
Conn.Close()
End If
End Sub
Public Function GetRS(SQL)
Set RS = Conn.Execute(SQL)
GetRS = RS
End Function
Public Function ExecuteSQL(SQL)
Conn.Execute(SQL)
End Function
End Class
You then make sure to call it before using the class and pass your ADODB.Connection object.
'Key is connection object is declared in the scope of the page
Dim conn: Set conn = Server.CreateObject("ADODB.Connection")
Call conn.Open("DSN=x")
'GET PAGED MEMBERS
Function GetMembers(page)
If Not IsNumeric(page) Or page = "" Then page = 1
Dim db : Set db = new classDB
'Call init() method and pass connection into the class instance.
Call db.Init(conn)
Set GetMembers = db.GetRS("SELECT * FROM member")
End Function
Related
I have an Employee class where I call my database connection Module to make a query.
I am getting "Compile Error: Expected function or variable", which I'm not understanding, because I have the empObj set at the top of the form.
I would like to return the value from the Employee.getEmployee method. Can someone please show me how to call the Employee class from my form? Do I have to import the class first? I don't believe VB6 supports the Imports keyword.
This is my form:
Option Explicit
Private empObj As New Employee
Private Sub Form_Load()
'For testing only
MsgBox (empObj.getEmployee)
End Sub
This is my class:
Public Sub getEmployee()
'ConnectSQL is a database connection
return ConnectSQL
End Sub
And this is the module:
Public Function ConnectSQL()
Set SQLMyconn = New ADODB.Connection
Set SQLRecset = New ADODB.Recordset
SQLMyconn.Open "Driver={MySQL ODBC Client Interface};ServerName=localhost;dbq=#testdb"
End Function
The basic shell of what you want to do is like this:
Option Explicit
Private empObj As Employee
Private Sub Form_Load()
Set empObj = New Employee
MsgBox empObj.getEmployee
End Sub
Public Function getEmployee() As String
getEmployee = ConnectSQL
End Function
Public Function ConnectSQL() As String
Set SQLMyconn = New ADODB.Connection
Set SQLRecset = New ADODB.Recordset
SQLMyconn.Open "Driver={MySQL ODBC Client Interface};ServerName=localhost;dbq=#testdb"
ConnectSQL = "data from your DB lookup"
End Function
Almost every line is different than what you posted, so carefully look at the code.
EDIT:
Based on a comment, here's how to modify the code to return a connection object:
Option Explicit
Private empObj As Employee
Private Sub Form_Load()
Set empObj = New Employee
MsgBox empObj.getEmployee
Dim MyConnection As ADODB.Connection
Set MyConnection = ConnectSQL()
'you can grab and use the connection in your form, too.
End Sub
Public Function getEmployee() As String
Dim MyConnection As ADODB.Connection
Set MyConnection = ConnectSQL()
'use the connection to grab data
getEmployee = "data from your DB lookup"
End Function
Public Function ConnectSQL() As ADODB.Connection
Set ConnectSQL = New ADODB.Connection
ConnectSQL.Open "Driver={MySQL ODBC Client Interface};ServerName=localhost;dbq=#testdb"
End Function
Don't forget to close your connection after you are done with it. To sum up the changes:
empObj - you should declare and instantiate your objects separately.
MsgBox - no need for the ().
Functions vs Subs - the first returns data, the second does not. Make sure you declare the return type of a function.
return - this statement is obsolete and doesn't do what you want. Instead, assign a value to the name of the function.
Dim xyzWkB As Excel.workbook
Set xyzWkB = setGetxyzObj(reportFile.Text)
populateListCombo (xyzWkB)
The function is defined as follows:
Public Function populateListCombo(activeWkB As Excel.workbook)
......
......
End Function
But in execution at the time of calling populateListCombo am getting the error "object does not support this property"
Here setGetxyzObj is defined as follows:
Public Function setGetxyzObj(Optional userInput As String) As Excel.workbook
Static xyz As New Excel.Application
Static xyzWkB As Excel.workbook
Set xyz = New Excel.Application
If Not (userInput = "") Then
Set xyzWkB = xyz.Workbooks.Open(userInput)
End If
Set setGetxyzObj = xyzWkB
End Function
I have also tried with populateListCombo (setGetxyzObj()), but still getting the same error.
Ok i have a class, a dbml file and a form. My project is called "Demo Project"
Form - DriveTimeActiveVendorsFrom
dbml - Dataworld
class - tblDriveTimeActiveVendors
My form contains the following code
Imports System.Data.Linq.Mapping
Public Class DriveTimeActiveVendorsForm
Private dc As New DataworldDataContext.DataworldDataContext
Dim _insert As New tblDrivetimeActiveVendors
Private Sub insertVendor()
dc = New DataworldDataContext.DataworldDataContext
_insert.ASRVendor = TextBox1.Text
_insert.AddressLine1 = TextBox2.Text
_insert.City = TextBox3.Text
dc.tblDriveTimeActiveVendors.InsertOnSubmit(_insert)
End Sub
End Class
My class contains the following
Public Class tblDrivetimeActiveVendors
Private _ASRVendor As String = Nothing
Private _AddressLine1 As String = Nothing
Private _City As String = Nothing
Public Property ASRVendor() As String
Get
Return _ASRVendor
End Get
Set(ByVal value As String)
If value Is Nothing Then
_ASRVendor = Nothing
Else
_ASRVendor = value.Trim
End If
End Set
End Property
Public Property AddressLine1() As String
Get
Return _AddressLine1
End Get
Set(ByVal value As String)
If value Is Nothing Then
_AddressLine1 = Nothing
Else
_AddressLine1 = value.Trim
End If
End Set
End Property
Public Property City() As String
Get
Return _City
End Get
Set(ByVal value As String)
If value Is Nothing Then
_City = Nothing
Else
_City = value.Trim
End If
End Set
End Property
Im getting an error on the following line
dc.tblDriveTimeActiveVendors.InsertOnSubmit(_insert)
Its the "_insert" part and the error is
Value of type 'WindowsApplication1.tblDrivetimeActiveVendors' cannot be converted to 'WindowsApplication1.DataworldEntity.tblDriveTimeActiveVendor'. C:\Users\rmonzing\Documents\Visual Studio 2008\Projects\DemoProject\DemoProject\DriveTimeActiveVendorsForm.vb 13 53 DemoProject
What am i missing here? Thanks
The variable _insert is declared as an object of type tblDrivetimeActiveVendors (plural), but InsertOnSubmit is expecting an object of type `tblDrivetimeActiveVendor' (singular).
Somewhere in your code, something has already declared a class tblDrivetimeActiveVendor, which (presumably) contains properties that correspond to the columns in your database table. You need to use this object instead of the class that you posted above.
I'm trying to create a helper class to easily build dynamic LINQ queries. Code is heavily modified version of this excellent CodeProject article: http://www.codeproject.com/Articles/493917/Dynamic-Querying-with-LINQ-to-Entities-and-Express which uses the PredicateBuilder here: http://www.albahari.com/nutshell/predicatebuilder.aspx
I'm still in the process of cleaning up the code so variables names are rubbish at the moment and there is not one comment in sight.
Usage
Dim conditions As New List(Of Condition)
With conditions
.Add(New Condition With {.Field = "EatsPeople", .Operator = "Equals", .Value = False})
.Add(New Condition With {.Field = "Name", .Operator = "Equals", .Value = "Adric"})
.Add(New Condition With {.Field = "Description", .Operator = "Contains", .Value = "ugly"})
End With
Dim predicate = BuildPredicate(conditions)
Dim tester = data.Monsters.AsExpandable.Where(predicate).ToList
Entity
Public Class Monster
Public Property EatsPeople As Boolean
Public Property Name As String
Public Property Description As String
End Class
Storage for search:
Public Class Condition
Public Property Field As String
Public Property [Operator] As String
Public Property Value As Object
End Class
Methods
Public Function BuildPredicate(conditions As List(Of Condition)) As Expression(Of Func(Of Monster, Boolean))
Dim predicate = PredicateBuilder.True(Of Monster)()
For Each c In conditions
Dim dbFieldName = c.Field
Dim dbType = GetType(Monster)
Dim dbFieldMemberInfo = dbType.GetMember(dbFieldName, BindingFlags.IgnoreCase Or BindingFlags.Public Or BindingFlags.Instance).Single()
predicate = BuildExpression(c, dbType, dbFieldMemberInfo, predicate)
Next
Return predicate
End Function
Private Function CreateLambda(value As Object, method As MethodInfo, ByVal dbType As Type, ByVal dbFieldMemberInfo As MemberInfo) As Expression(Of Func(Of Monster, Boolean))
Dim dbTypeParameter = Expression.Parameter(dbType, "x")
Dim dbFieldMember = Expression.MakeMemberAccess(dbTypeParameter, dbFieldMemberInfo)
Dim criterionConstant = New Expression() {Expression.Constant(value)}
Dim containsCall = Expression.Call(dbFieldMember, method, criterionConstant)
Return TryCast(Expression.Lambda(containsCall, dbTypeParameter), Expression(Of Func(Of Monster, Boolean)))
End Function
And the problematic method
Private Function BuildExpression(condition As Condition, ByVal dbType As Type, ByVal dbFieldMemberInfo As MemberInfo, ByVal predicate As Expression(Of Func(Of Monster, Boolean))) As Expression(Of Func(Of Monster, Boolean))
Dim type = condition.Value.GetType
Dim method As MethodInfo = type.GetMethod(condition.Operator, BindingFlags.Instance Or BindingFlags.Public, Nothing, {type}, Nothing)
If type = GetType(String) Then
If condition.Value.ToString.Contains(",") = True Then
Dim inner = PredicateBuilder.False(Of Product)()
For Each v In condition.Value.ToString.Split(",")
inner = inner.Or(CreateLambda(v, method, dbType, dbFieldMemberInfo))
Next
*****Return predicate.And(inner)*****
End If
End If
Return predicate.And(CreateLambda(condition.Value, method, dbType, dbFieldMemberInfo))
End Function
What is the problem?
The line in the last method surrounded by five asterisks is the issue.
When adding the OR grouped expression to the original predicate builder you get
The parameter 'f' was not bound in the specified LINQ to Entities
query expression.
For some reason, I can't seem to create a nested expression.
If you put the code above where the query is executed in usage sample, it works (after making some mods).
Update with solution:
The line with the asterisks needs to change to
Return predicate.And(inner.Expand)
I'm not a Visual Basic person, but in the C# implementation I think you'd probably need to add AsExpandable() to your query as per albahari.com/nutshell/predicatebuilder.aspx.
I'm getting this exception thrown when I run my tests:
Test method OuvertureClasseur threw exception: System.Runtime.InteropServices.InvalidComObjectException: COM object that has been separated from its underlying RCW cannot be used...
though each of my test passes when ran individually.
Here's my tests code:
<TestClass()> _
Public Class FabriqueExcelTests
Private Shared _xl As ApplicationClass
<ClassInitialize()> _
Public Shared Sub MyClassInitialize(ByVal testContext As TestContext)
_xl = New ApplicationClass()
_xl.Visible = False
_xl.ScreenUpdating = False
_xl.DisplayAlerts = False
End Sub
<ClassCleanup()> _
Public Shared Sub MyClassCleanup()
_xl.Quit()
_xl = Nothing
End Sub
<TestMethod()> _
Public Sub ConstructeurParDefaut()
Dim gestionnaire As GestionnaireExcel = New GestionnaireExcel()
Assert.IsNotNull(gestionnaire)
Assert.IsInstanceOfType(gestionnaire, GetType(GestionnaireExcel))
End Sub
<TestMethod()>
Public Sub CreationDUnFichierExcel()
Dim fichier As String = "C:\Temp\CreationFichierExcel.xls"
Using xl As GestionnaireExcel = New GestionnaireExcel()
Dim classeur As Workbook = xl.CreerClasseur(fichier)
classeur.Close()
classeur = Nothing
End Using
Assert.IsTrue(File.Exists(fichier))
File.Delete(fichier)
End Sub
<TestMethod()> _
Public Sub OuvertureClasseur()
Dim fichier As String = "C:\Temp\OuvertureClasseur.xls"
_xl.Workbooks.Add(XlWBATemplate.xlWBATWorksheet)
_xl.ActiveWorkbook.SaveAs(fichier)
_xl.ActiveWorkbook.Saved = True
_xl.Workbooks.Close()
Using xl As GestionnaireExcel = New GestionnaireExcel()
Dim classeur As Workbook = xl.OuvrirClasseur(fichier)
Assert.AreEqual(fichier, classeur.FullName)
classeur.Close()
classeur = Nothing
End Using
File.Delete(fichier)
End Sub
End Class
And my GestionnaireExcel class:
Public Class GestionnaireExcel
Implements IDisposable
Private _cultureOriginale As CultureInfo
Private _disposedValue As Boolean = False '' To detect redundant calls
Private _excel As ApplicationClass
Public Sub New()
InitialiserExcel()
End Sub
'' IDisposable
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not Me._disposedValue Then
If disposing Then
'' TODO: free other state (managed objects).
If (_excel IsNot Nothing) Then
_excel.Quit()
_excel = Nothing
System.Threading.Thread.CurrentThread.CurrentCulture = _cultureOriginale
End If
End If
'' TODO: free your own state (unmanaged objects).
'' TODO: set large fields to null.
End If
Me._disposedValue = True
End Sub
'' This code added by Visual Basic to correctly implement the disposable pattern.
Public Sub Dispose() Implements IDisposable.Dispose
'' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above.
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
Public Function CreerClasseur(ByVal classeur As String) As Workbook
_excel.Workbooks.Add(XlWBATemplate.xlWBATWorksheet)
_excel.ActiveWorkbook.SaveAs(classeur)
Return _excel.ActiveWorkbook
End Function
Private Sub InitialiserExcel()
_cultureOriginale = System.Threading.Thread.CurrentThread.CurrentCulture
System.Threading.Thread.CurrentThread.CurrentCulture = New CultureInfo("en-US")
_excel = New ApplicationClass()
_excel.DisplayAlerts = False
_excel.ScreenUpdating = False
_excel.Visible = False
End Sub
Public Function OuvrirClasseur(ByVal fichier As String) As Workbook
Dim classeur As Workbook = _excel.Workbooks.Open(fichier _
, False, False _
, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing _
, False _
, Type.Missing, Type.Missing _
, False _
, Type.Missing, Type.Missing)
Return classeur
End Function
End Class
Related questions found
Though I have read and understand these questions and answers, I don't seem to find what causes my OuvertureClasseur() test to fail when I run all my tests together, and it works just fine when I run it individually.
COM object that has been separated from its underlying RCW cannot be used.
WMI Exception: “COM object that has been separated from its underlying RCW cannot be used”
COM object that has been separated from its underlying RCW cannot be used.
COM object that has been separated from its underlying RCW can not be used - why does it happen?
WPF Thread: “COM object that has been separated from its underlying RCW cannot be used.”
I have been running around for few hours now, and any help will gladly be appreciated.
Thanks in advance! =)
Excel's executing as another process. It's possible that what's happening in classeur.Close() is asynchronous, and that some of it is taking place after the GestionnaireExcel instance is disposed.
Try commenting out the using block and see what happens.