I have a VB6 application that takes a recordset as a parameter in one of its functions. I am using ADODB in a .NET project to create and pass the recordset to the VB6 project. When I create the recordset in VS2010 by connecting to the database and then disconnecting, all is well:
con.ConnectionString = "Provider=SQLOLEDB.1;Data Source=MyDB;Initial Catalog=IC;User ID=user;Password=pass"
rs.ActiveConnection = con
rs.Open("SELECT * FROM Table1")
rs.ActiveConnection = Nothing
However, when I create the recordset by copying the data from a .net DataTable: rsRecordSet = New ADODB.Recordset
For Each dtDataColumn As DataColumn In dtDataTable.Columns
Select Case dtDataColumn.DataType.UnderlyingSystemType.ToString
Case "System.Boolean" : dteRecordSetDataType = DataTypeEnum.adBoolean
Case "System.Byte" : dteRecordSetDataType = DataTypeEnum.adUnsignedTinyInt
Case "System.Char" : dteRecordSetDataType = DataTypeEnum.adChar
Case "System.DateTime" : dteRecordSetDataType = DataTypeEnum.adDate
Case "System.Double" : dteRecordSetDataType = DataTypeEnum.adDouble
Case "System.Int16" : dteRecordSetDataType = DataTypeEnum.adSmallInt
Case "System.Int32" : dteRecordSetDataType = DataTypeEnum.adInteger
Case "System.Int64" : dteRecordSetDataType = DataTypeEnum.adBigInt
Case "System.SByte" : dteRecordSetDataType = DataTypeEnum.adTinyInt
Case "System.Single" : dteRecordSetDataType = DataTypeEnum.adSingle
Case "System.UInt16" : dteRecordSetDataType = DataTypeEnum.adUnsignedSmallInt
Case "System.UInt32" : dteRecordSetDataType = DataTypeEnum.adUnsignedInt
Case "System.UInt64" : dteRecordSetDataType = DataTypeEnum.adUnsignedBigInt
Case "System.Guid" : dteRecordSetDataType = DataTypeEnum.adGUID
Case "System.String" : dteRecordSetDataType = DataTypeEnum.adVarChar
Case Else : dteRecordSetDataType = DataTypeEnum.adVarChar
End Select
If dtDataColumn.AllowDBNull Then
faeRecordSetAttribute = FieldAttributeEnum.adFldIsNullable
Else
faeRecordSetAttribute = FieldAttributeEnum.adFldUnspecified
End If
rsRecordSet.Fields.Append(dtDataColumn.ColumnName, dteRecordSetDataType, dtDataColumn.MaxLength, faeRecordSetAttribute)
Next
rsRecordSet.CursorLocation = CursorLocationEnum.adUseClient
rsRecordSet.CursorType = CursorTypeEnum.adOpenDynamic
rsRecordSet.LockType = LockTypeEnum.adLockOptimistic
rsRecordSet.ActiveConnection = Nothing
rsRecordSet.Open()
For Each dtDataRow As DataRow In dtDataTable.Rows
rsRecordSet.AddNew()
For Each rsField As ADODB.Field In rsRecordSet.Fields
Select Case rsField.Type
Case DataTypeEnum.adBoolean : rsField.Value = Convert.ToBoolean(dtDataRow.Item(rsField.Name))
Case DataTypeEnum.adGUID : rsField.Value = "{" & dtDataRow.Item(rsField.Name).ToString & "}"
Case Else : rsField.Value = dtDataRow.Item(rsField.Name)
End Select
Next
Next
Return rsRecordSet
...my VB6 project rejects it right away with errors such as "Operation is not allowed in this context" and "The callee (server [not server application]) is not available and disappeared; all connections are invalid. The call may have executed. (Exception from HRESULT: 0x80010007 (RPC_E_SERVER_DIED))". I have also been having an impossible time debugging the two project together (it worked at one point) to see where in the VB6 project the recordset is being rejected, but I have a feeling it is happening before it even goes into my VB6 function.
I am hoping someone can explain to me the difference between the two different recordsets. Is there information in one recordset somewhere that indicates that it was at one time connected to a database source? Is there a way I can "select" from my existing datatable so that the recordset thinks it pulled from somewhere?
Thanks in advance!
.Net defaults to disconnected recordsets, but VB6 doesn't. The recordset that you have opened in your code is a Dynamic recordset, which is incapable of operating without an open connection. The dynamic cursortype means that all changes to your recordset are posted immediately to the database. When you closed your connection, you couldn't do that anymore. Your errors suggest that the dynamic cursor looked for a connection when you tried to add a new record, and couldn't find one.
You might be interested to check whether your CursorLocation is still adUseClient. It shouldn't be; once you set the type to dynamic, the cursor has to be server side. Either your cursor is static or your location is server.
So, to make a disconnected recordset the properties have to be:
.CursorLocation = adUseClient
.CursorType = adOpenStatic 'This is automatic as a result of the previous line
.LockType = adLockBatchOptimistic
This last has to do with making batch changes on the disconnected recordset, and then when ready to post locking for the whole batch, posting the records, and then going through a conflict resolution procedure. Anyway, see if that helps you. It should.
A little more: if you just set your location to client-side, the type will default to static. It's the only cursortype that works client side. Kind of makes sense; you're working with a local "snapshot" of your data if it's on the client side.
Here is a simple explanation from back in 1999, when this was cutting edge stuff. :)
User contributions licensed under CC BY-SA 3.0