I was wondering if someone could explain the difference between an ADODB.Connection and creating an Oracle session through "OracleInProcServer.XOraSession". Is one better than the other in certain cases?
From what I have read in ADODB cnn.Open "Pubs", "MyUserName", "MyPassword" and OraSession you put in openDatabase(database_name, database_version, database_displayname, database_size).
How do the connections differ?
Also with the ADODB connection you can open a recordset and save with a rs.Open and a rs.GetRows. Is there a way to save the values of the query to then display in the Excel with the OraSession connection?
Dim cnn As ADODB.Connection
Dim rs As ADODB.Recordset
verses
Set OraSession = CreateObject("OracleInProcServer.XOraSession")
Set OraDatabase = OraSession.DbOpenDatabase("", "", 0&)
Thanks!
Maggie
Overall, both are tools to connect databases to programming environments. According to online docs, OracleInProcServer is an OLE Automation Object. Hence, after install it comes available as a VBA reference. ADODB (part of ADO) is a general database API and the other is a specific Oracle API. See further points below. Do note: I am not familiar with OracleInProcServer but below gathers from above source.
ActiveX Data Objects (ADO)
Generializable API: capable of swapping out connection strings and maintaining same consistent codebase across both OLEDB providers and ODBC drivers such as Oracle, MySQL, SQL Server, PostgresSQL, more; see example of MS Access and SQLite interchange;
Full-featured database API for working between application layer and backend database including calling stored procedures, action queries, working with recordsets, etc.;
COM or .DLL object not limited to VBA but any language that can make a COM interface (i.e,. Java, PHP, Python, R) as initialized with CreateObject("ADODB.Connection");
Since it integrates into a programming language, it can connect to the Excel object library (i.e., workbooks, worksheets, ranges), even Access/Word/Outlook/PowerPoint apps;
Microsoft is the vendor and maintainer; API is available for free download. However, usually no additional installation is required as ADO ships with MS Office software or Windows OS;
Widely known in the industry with time-enduring problem and solutions available in many tutorials, books, and online searches.
OracleInProcServer
Specific API: Customized and tailored solution specifically for Oracle (proprietary software) and no other database, so possibly is keen to Oracle-specific methods;
Appears to be a capable database API working with database, dynaset, and field objects;
COM or .DLL object not limited to VBA but any language that can make a COM interface as seen with initialization: CreateObject("OracleInProcServer.XOraSession");
Docs show dynasets can work with Excel workbooks, looping across records and fields (very similar to ADO) to display data:
'Display Data
For Rownum = 2 To myDynaset.RecordCount + 1
For Colnum = 0 To fldcount - 1
ActiveSheet.Cells(Rownum, Colnum + 1) = flds(Colnum).Value
Next
myDynaset.MoveNext
Next
Oracle is the vendor and maintainer and installation (possibly paid) is required; maybe it is installed with Oracle client and other components; plus users may be able to call someone for help with this product (check service agreement/terms);
Likely a small user base that may not have sophisticated issues resolved or solutions widely known or available.
Which one is better? This ultimately comes down to your preference or project needs. For simple tasks of connecting to database, calling queries, and outputting to Excel any above will do.
Related
ALL,
Is there a query which will give me the version of the mdb/accdb file created?
Or this info is not stored anywhere?
Background:
I'm working on C++ program, connecting with ODBC driver and want to know ACCESS version behind this file.
TIA!!
Short answer: No
It has been requested from many to have an option to check if a database file supports, say, BigInt or DateTime2 but, currently, you are left with trial-n-error.
However, if you don't plan to modify the scheme, your only concern should be, if the database file is of the old mdb (JET) form or the newer (introduced 14 years ago) accdb (ACE) format.
You can easily obtain that information using DAO, the Database.Version property.
In vbscript, that'd look like this:
Dim dbe
Set dbe = CreateObject("DAO.DbEngine")
Dim db
Set db = dbe.OpenDatabase("C:\Path\To\Db.accdb")
WScript.Echo db.Version 'E.g. 14.0 for Office 2010
Using COM is a lot more verbose in C++ so I'll leave that to you, but the approach could be the same.
Using only ODBC, I'm not sure how to obtain this information, though.
I am looking for some help on retrieving Access 2007 database schema information for system object tables. I have reviewed, read and tested this successfully for the non system tables. The database tables info I am trying to retrieve are in the tables that begin with MSys{xxxxxxxxxx} and store things like relationships, creation date, dateupdate, etc. This tables are viewable by right clicking on the Navigation Options popup menu in Access and selecting Show System Objects.
For clarification, I have added the System.mdw database to the connection string, and I have attempted multiple settings in the restrictions property of the getSchema method. I am using ado.net, vb.net, and VS2008, these are access 2007 databases not mdb files.
My issue appears to continue to be no read access to the System tables. My end goal is to manage relationships initially and eventually hopefully script these databases much like can be done EASILY (Microsoft) in SQL Server Mgmt Studio.
I am hoping someone can point me to some good web link resources or even a good book that clearly discusses this functionality.
thanks,
As it turns out the easiest way to gain access to the system table data is to execute a permissions command on the Systems database table(s). The following query did the trick....
Dim strDdl As String = "GRANT SELECT ON MSysObjects TO Admin;"
Dim command12 As New OleDbCommand(strDdl, connection)
I need to query Active Directory and build my MS Access database using the results. I found some code here. As you can see, part of this code is creating an ADODB.Connection object. Is this the only method for connecting to AD? Is it possible to use DAO objects?
I've never taken any courses on databases so forgive me if this question makes no sense.
Thanks!
As you can see part of this code is creating an ADODB.connection object. Is this the only method for connecting to AD? Is it possible to use DAO objects?
Personally I wouldn't recommend trying to use DAO to query AD. DAO works very well to manipulate Access database tables from within Access itself, but for Access VBA code to manipulate any data source that isn't...
a local Access table or
an Access "linked table"
...I would recommend using ADO. You can use the code samples in the article you cited, and if you run into any difficulties you will be much more likely to receive meaningful assistance.
Background
The main application where I work is based heavily on the MUMPS-esque Caché database engine from InterSystems. Everything is stored in global arrays. Getting data out of the system for external reporting ranges from simply being a pain to being egregiously slow and painful.
Caché provides an ODBC driver for the database but unless the global arrays involved happen to be keyed by the selection criteria, it resorts to scans and a simple query will take hours to run. For scale, the entire Caché production namespace is about 100GB. I can write ObjectScript (Intersystems' dialect of MUMPS) programs that pull data much faster than the ODBC driver in these cases.
Part of the problem I think is that the application vendor doesn't use Caché's object persistence support but instead has the SQL tables defined as a façade over the global arrays, and it often doesn't work well for batch requests.
I built a reporting database in MS SQL Server that pulls the most common data (2.5GB worth) and even if it has to scan every table, all results are returned within 3 seconds. Unfortunately, it takes a long time to refresh the data so I can only do a full refresh once a week and an active refresh once a day. This is good enough for most needs, but I want to do better.
I'm on Caché 2007, SQL Server 2008 R2, VS2010 on Windows 7 and Windows Server 2008 R2.
Scope of question
I need a way to integrate live data from the source Caché database with other data on SQL Server. I want to be able to integrate views or table valued functions into a SQL query and have it pull live data from the source db.
The live data must be available within SQL Server for processing. Doing it with a secondary application would be a huge pain and wouldn't work with reporting tools that just expect to push a query over ODBC and get a final dataset in the right format.
I understand that there are ways to get data into SQL Server or accomplish the same general things I want to do. That's not what this question is about.
The data needs to come from ObjectScript programs run on Caché since not all the data I need is exposed through the SQL defined tables and I get the control I need to make the performance usable with ObjectScript.
I am looking for advice on any new options or how I can improve one of the options I've tried or considered or other pros or cons for those approaches.
What I've tried so far
This project has been an exercise in frustration where each promising avenue I've looked into is either terrible or doesn't work for some reason. Often the reason is some unnecessary restriction on SQLCLR assemblies.
Pulling everything through InterSystem's Caché ODBC driver via a linked server. SQL Server often resorts to scans if it can't push conditions to the remote server or has to perform a join locally. A scan of any nontrivial table takes many hours and is unacceptable. Also, the length of many columns is incorrectly defined by the SQL table definitions in Caché; SQL Server doesn't like that and aborts the query. See this SO question. I can't change the table defs and the vendor doesn't think it's a problem because it works with MS Access.
Using OPENQUERY on demand. This works to some extent but I can still have the column length problem from the previous item and there's no way to parameterize OPENQUERY queries so that makes it pretty useless to pull contextual data.
Using SQLCLR to call the ODBC data provider through CLR table valued functions. This takes care of the parameterization and data length issues, although it does require me to define or modify a function each time I need a new piece of data. Unfortunately, not all the data elements I'm interested in are available through SQL. For some things, I need to access the global arrays directly.
Intersystems provides an ActiveX control that lets you run ObjectScript programs over TCP on the server and get the results. This works great in a stand-alone C# app but as soon as I try to make a connection from a SQLCLR assembly I get a ridiculous URI error:
A .NET Framework error occurred during execution of user-defined routine or aggregate "GetActiveAccounts":
System.UriFormatException: Invalid URI: The URI is empty.
System.UriFormatException:
at System.Uri.CreateThis(String uri, Boolean dontEscape, UriKind uriKind)
at System.Uri..ctor(String uriString)
at System.ComponentModel.Design.RuntimeLicenseContext.GetLocalPath(String fileName)
at System.ComponentModel.Design.RuntimeLicenseContext.GetSavedLicenseKey(Type type, Assembly resourceAssembly)
at System.ComponentModel.LicenseManager.LicenseInteropHelper.GetCurrentContextInfo(Int32& fDesignTime, IntPtr& bstrKey, RuntimeTypeHandle rth)
at FacsAccess.GetActiveAccounts.Client.connect()
at FacsAccess.GetActiveAccounts.Client..ctor()
at FacsAccess.GetActiveAccounts.E1.GetEnumerator()
See this unanswered SO question. There are other postings about it on the net but no one seems to have a clue. This is an extremely simple COM wrapper over a C++ DLL; it's not doing anything with licensing and has no reason to be in the managed licensing libraries. I wonder if this is some kind of boilerplate that's trying to get the name for an assembly that doesn't have a name because it's been loaded into the SQL database.
Intersystems also provides a more direct unmanaged interface but those interfaces are all C++, which I can't use through P/Invoke and I can't load a C++/CLI mixed mode impure assembly in SQLCLR.
Options I've considered but seem kind of terrible
I've considered trying the ActiveX control through SQL Server's COM support but that's terribly slow and really cumbersome.
I could create an out of process service to proxy the traffic but I can't use .NET remoting from SQLCLR and you're not supposed to use WCF and it would be really heavy weight for a such a simple interface anyway. I'd sooner roll my own IPC interface.
I could write some kind of extra unmanaged wrapper with a C style interface for the VisM or CacheDirect interfaces and access THAT through P/Invoke.
It doesn't seem like this should be so hard but it's really driving me up the wall and I need some perspective.
I think you can use ODBC via a linked server accessing stored procedures on the Cache database that are visible to the ODBC driver and that return result sets, but are not implemented using SQL.
I am 100% certain you can create such stored procedures and access them via ODBC, but I have never tried accessing them from SQL server as a linked server. Even if the linked server doesn't work, it seems like it would be preferable to access via the Intersystem's ODBC driver rather than the Active X control or CacheDirect.
I have an example of such a procedure for this question.
In case that link dies, here is the code:
Query OneGlobal(GlobalName As %String) As %Query(ROWSPEC = "NodeValue:%String,Sub1:%String,Sub2:%String,Sub3:%String,Sub4:%String,Sub5:%String,Sub6:%String,Sub7:%String,Sub8:%String,Sub9:%String") [SqlProc]
{
}
ClassMethod OneGlobalExecute(ByRef qHandle As %Binary, GlobalName As %String) As %Status
{
S qHandle="^"_GlobalName
Quit $$$OK
}
ClassMethod OneGlobalClose(ByRef qHandle As %Binary) As %Status [ PlaceAfter = OneGlobalExecute ]
{
Quit $$$OK
}
ClassMethod OneGlobalFetch(ByRef qHandle As %Binary, ByRef Row As %List, ByRef AtEnd As %Integer = 0) As %Status [ PlaceAfter = OneGlobalExecute ]
{
S Q=qHandle
S Q=$Q(#Q) b
I Q="" S Row="",AtEnd=1 Q $$$OK
S Depth=$QL(Q)
S $LI(Row,1)=$G(#Q)
F I=1:1:Depth S $LI(Row,I+1)=$QS(Q,I)
F I=Depth+1:1:9 S $LI(Row,I+1)=""
S AtEnd=0
S qHandle=Q
Quit $$$OK
}
FYI, that is not an example to use in production, since it exposes all the data from all the globals.
However, it sounded like you were prepared to write Cache Object Script to directly get the data anyway - this is a template for doing so. The main thing to understand is that qHandle will be passed back by the ODBC driver on each call, so you can use it to store state. If there is a lot of state, make qHandle be an integer index into a temporary global holding the "real" state, and clean that up in the close method.
Since you are concerned about performance, you may want to also implement a
MyQueryFetchRows (ByRef qHandle As %Binary, FetchCount As %Integer = 0, ByRef RowSet As %List, ByRef ReturnCount As %Integer, ByRef AtEnd As %Integer) As %Status
method - see the documentation for %Library.Query for more details.
If you really need this to appear to ODBC as a (read-only) table rather than a stored procedure I think it might be possible - but I've never before tried to see if an arbitrary stored procedure can be exposed as a read-only table and I'm not sure how easy it is, or if it's actually always possible.
I am here to write a small database application that will be running in desktop (offline mode).
I am using MSAccess 2007 as my database file and trying to write code in vb.net.
I used to write the code vb6 an usually had global variables for storing database connection and executing every query from that.
I am trying to upgrade myself from vb6 to vb.net.
do i need to read some more simple starter books also?
In .NET, talking to a database is handled with ADO.NET, which uses something called "connection pooling". The connection pool is basically a collection of open connections to your database that ADO.NET manages for you. In your code, when you create and open a Connection object, ADO.NET first looks in the connection pool to see if it already has an open connection to your data source, and if it finds one it uses that (instead of actually creating and opening a new connection). When you close your connection, ADO.NET does not really close it, but instead returns it to the connection pool.
Therefore, you do not need (and in face do not want) to maintain open connection objects inside your application (in a global variable or anywhere). The correct approach with data access in ADO.NET is to create and Open a Connection object, do whatever you need to do with the database, and then Close and Dispose your Connection.
Store the connection string in the config file (in the solution explorer, open the My Project folder and doubleclick on Settings.settings).
I'd suggest that you create one or more classes to contain your database code and let those classes convert between the database data and your application objects, most VB6 projects I saw had the GUI hard linked to the DB which can make future maintenance or new features very difficult and limits the possiblity of code reuse.
If you've got VB6 experience I'd thought that you could probably start trying to create the application right away but you should definitely read either a good book or good articles about it at the same time so that you pick up things like that you need to Dispose of your database objects after user etc.
It's probably a good idea to get a book, a lot has changed since VB6.
Also consider using a more robust db, like SQL compact or SQLite. It will allow you you use the Entity Framework which will make writing your app a whole lot easier.