C# Generic methods for database driver access in ADO.NET - database

I have to write a small C# program which will handle at least three differents database vendors (Oracle, Sybase ASE, SqlServer) in a dynamic way. (It will rely on customer choices to choose the database)
I decided to use "pure" managed drivers through ado.net data providers.
But, when I just try connecting, I expected code a la "One line to rule them all", just like JDBC does with :
DriverManager.getConnection(connection_string);
Instead of this, surprised, I have to write for each driver its specific code :
SqlConnection() for SqlServer
AseConnection() for Sybase
OracleConnection(), etc.
Of course, I should encapsulate -by myself- all of this inside abstract methods and dynamic loadings, but I'm wondering why such a thing doesn't already exist in .net
Mmhhh, I've got the feeling that I'm missing something

Since you have the .Net Provider for he respective database installed on the machine, you can use the DbProviderFactory, for sample:
include
using System.Data.Common;
and try something like this:
// create the provider factory from the namespace provider
DbProviderFactory factory = DbProviderFactories.GetFactory("System.Data.SqlClient");
// you could create any other provider factory.. for Oracle, MySql, etc...
// use the factory object to create Data access objects.
DbConnection connection = factory.CreateConnection(); // will return the connection object, in this case, SqlConnection ...
connection.ConnectionString = "read connection string from somewhere.. .config file for sample";
try
{
// open connection
connection.Open();
// create command to execute queries...
DbCommand command = connection.CreateCommand(); // create a SqlCommand, OracleCommand etc... depende of the provider factory configured.
// some logic
}
catch
{
}
finally
{
// close connection
connection.Close();
}
To know, what providers your application can find, you can use the DbProviderFactories.GetFactoryClasses() method to get a DataTable with details of every provider installed on the machine.

Related

How to execute SqlCommand using OLEDB connection in SSIS script component

I am using SSIS 2019 and am able to execute SQL Command with ADO.Net Connection Manager.
I want to use OLEDB connection manager in a Script component within a Data Flow Task and I am getting the below error:
System.InvalidCastException: Unable to cast COM object of type 'System.__ComObject' to class type 'System.Data.SqlClient.SqlConnection'. Instances of types that represent COM components cannot be cast to types that do not represent COM components; however they can be cast to interfaces as long as the underlying COM component supports QueryInterface calls for the IID of the interface.
Can someone please let me know if we can use OLEDB Connection in SSIS script component in a Data flow.
Here is code for connection strings
public override void PreExecute()
{
string conn = this.Connections.Connection.ConnectionString;
}
I am not getting build error in script C# code. But getting error at script component.
Using a Script Component
To access a connection manager within a script component, you should first specify this connection manager from the script component editor as shown in the image below:
Then, within the script component, you should use the Connections variable to access this connection manager (In this example, the connection manager assigned name is Connection):
var constr = Connections.Connection.ConnectionString;
screenshot
Executing a SQL command using C#
Next, you should use this connection string to initiate a SqlConnection object in order to use it by a SqlCommand as follows:
using(SqlConnection conn = new SqlConnection(constr))
{
using (SqlCommand cmd = new SqlCommand("Write here your SQL command", conn))
{
conn.Open();
cmd.ExecuteNonQuery();
}
}
Make sure you added a reference for using System.Data.SqlClient to use the SqlConnection and SqlCommand objects.
Important Note: If you are using SQL authentication, you should re-add the password to the connection string since it will not be retrieved from the connection manager for security reasons.
Using a Script Task
You should first retrieve the OLE DB connection string from the connection manager using the following command:
string constr = Dts.Connections["OledbCM"].ConnectionString;
Demonstration
I added Messagebox.Show(constr) command to the script task to show how the connection string looks like once retrieved:
Helpful Links:
SSIS Script Task : ConnectionString for ADO.Net & OleDb ConnectionManager
Check OLDEDB database Connection using script task in SSIS
Update 1: SqlConnection vs. OleDbConnection
Since you are using SqlConnection class which represents a connection to a SQL Server database. You will encounter the following error while trying to use the connection string retrieved from an OleDb Connection:
Keyword not supported "Provider"
The main reason is that the OleDB connection requires that the connection string contains the provider information since it has the ability to connect to different providers such as Oracle, Excel, Access, SQL. While SqlConnection class does not support this information since it is only using the SQL Server Native client provider.
How to solve this issue?
You can simply use a System.Data.OleDb.OleDbConnectionStringBuilder object to remove this part using the following code:
string con = Dts.Connections["OledbCM"].ConnectionString;
var connBldr = new OleDbConnectionStringBuilder(con);
connBldr.Remove("Provider");
con = connBldr.ConnectionString;
Or you can use Linq: (Remember to add the System.Linq namespace)
string con = Dts.Connections["OledbCM"].ConnectionString;
con = string.Join(";", con.Split(';').Where(c =>
!c.TrimStart().StartsWith("Provider")));
References
How do I remove "Provider=..." from a connection string

Connecting Sql-database to wcf web sevice

I am trying to learn how to build a web service with WCF in .Net framework 4.5 using Visual Studio 2019, and I am trying to connect my service to a database already created which I want to do operation on through that web service, my exact question is: how to open a connection between the two things using SQlConnection class?, beacause I saw the constructors of the SqlConnection but I could't understand where can we write the address/Path of our database?
It may be a little bit stupid question, but I need a better explanasion than the one that exists on the Microsoft web site.
Here is my code, which describes a void method that creates the connection string. and then we call it every time we creat a connection.
Note: DataSource is the server address, IntitialCatalog is the database name
private void ConnectToDB(string datasource, string initialcatalog)
{
SqlConnectionStringBiulder ConnectionStringBuilder = new SqlConnectionStringBuilder()
{
DataSource = datasource,
InitialCatalog = initialcatalog,
IntegratedSecurity = true
};
SqlConnection connection = new SqlConnection(ConnectionStringBuilder.ToString());
SqlCommand command = connection.CreateCommand();
}
Obviously we can add the other available attributes to the connection string, and modify them as we want.

How do I generically reference a local table in a SQL Server database from an assembly installed in that database?

Let's say I have an assembly with a method does_stuff() that I've installed in an SQL server database. I want this method/storedproc to refer to a specific known table in the database. How do I get does_stuff to access the contents of the table without ever knowing where itself is hosted?
Let's say does_stuff is supposed to access table info_config.
If it was hosted in database ALPHA, it would access ALPHA.info_config
If it was hosted in database BETA, it would access BETA.info_config
I know how to open DB connections etc with ADO.NET, but those require specific server and database strings. I need flexibility so that the assembly does the same thing no matter where it is hosted.
Google search is giving me nothing.
Thanks in advance
All you have to do is use a context connection.
At the moment it may not seem obvious, but CLR code always executes in some context. There is always something (somebody) that executed the code directly or in some parent scope (stored procedure calls CLR function, CLR trigger fires on insert etc). When program execution reaches context connection, it just takes connection parameters (server, database, SET options etc) of that scope.
I want this method/storedproc to refer to a specific known table in the database.
After context connection is opened, you are querying your database as usual.
using (SqlConnection conn = new SqlConnection("context connection=true"))
{
conn.Open();
SqlCommand cmd = new SqlCommand("SELECT * FROM MyTable");
SqlContext.Pipe.ExecuteAndSend(cmd);
}

ServiceStack OrmLite with multiple Database Servers

I'm building an app around the servicestack framework and need to be able to access data in both Oracle and MS Sql Server. Is this possible using ORMLite, it seems that I can only set a single dialect for the App or have I missed something?
Yes it is possible and support for this is already built into the OrmLiteConnectionFactory, see the Master SQLServer + Sqlite shard example on OrmLite's project home page.
Basically you would register your default (or master) connection first with:
var dbFactory = new OrmLiteConnectionFactory(
"Data Source=host;Initial Catalog=RobotsMaster;Integrated Security=SSPI",
SqlServerDialect.Provider);
Then you would register a named connection for every other connection you wish to support, e.g:
dbFactory.RegisterConnection("shard-1",
"~/App_Data/{0}.sqlite".Fmt(shardId).MapAbsolutePath(),
SqliteDialect.Provider);
Once that's configured, opening a connection without specifying a name will open a connection to the default database, e.g:
using (IDbConnection db = dbFactory.OpenDbConnection()) { ... } //Default DB
Whilst you can specify a name to open up a named connection to a db with a different provider, e.g:
using (var dbShard = dbFactory.OpenDbConnection("shard-1")) { ... } //Named DB
Manually use different Dialect Providers
The differences between the SQL Provider implementations between different RDBMS's are contained within each dialect provider. So if you want to use OrmLite's convenience extension methods against an specific ADO.NET provider implementation you just need to assign the ThreadStatic DialectProvider you wish to use, e.g:
OrmLiteConfig.DialectProvider = SqlServerDialect.Provider;
var dbConn = new SqlConnection(SqlServerConnString);
dbConn.Select<Table>(); //All db access now uses the above dialect provider
This is essentially all what RegisterConnection in OrmLiteConnectionFactory automatically does behind the scenes for you.
For reference here are all the dialect providers for OrmLite up to this point:
SqlServerDialect.Provider
SqliteDialect.Provider (different 32/64 and Mono impls available)
MySqlDialect.Provider
PostgreSqlDialect.Provider
OracleDialect.Provider
FirebirdDialect.Provider

Why does sqlConnection.Close() not close the login?

We have unit tests to test that our database install and uninstall features successfully work.
The unit tests use the SqlClient.SqlConnection class to check the database contents before, during and after.
Our problem is that after using SqlClient.SqlConnection, the drop login part of the uninstall fails because it claims that a user is currently logged in. Even though we have called SqlConnection.Close(), the login seems to be still open.
Our code looks a little like this:
InstallTables(); // function uses smo to create tables in a database.
string connString = CreateLogin("userName", "password"); // create login with smo
// Test the returned connection string connects to the database
using (SqlConnection con = new SqlConnection(connString))
{
con.Open();
//test code to read the DB version out of a table
//Dispose calls con.Close() - I have also tried calling it explicitly
}
DropTables(); // uses smo to drop tables from the database
DropLogin("userName", "password"); // uses smo to drop the login
The DropLogin fails with the following exception:
System.Data.SqlClient.SqlException: Could not drop login 'engageSecurity_unittest_129418264074692569' as the user is currently logged in.
If I remove all the SqlConnection code until after the DropLogin, then everything runs fine.
Does anyone know why the user is not logged out when I call SqlConnection.Close() ?
Is this something to do with connection pooling?
Unless you're explicitly disabling Connection Pooling in your connection string, my guess is that even though you're disposing the connection it is still alive in the Connection Pool (in case you decide to re-use it):
SQL Server Connection Pooling (ADO.NET)
Try disabling Connection Pooling (by adding Pooling=false; in your connection string) and see what happens.
Alternatives to Pooling=false are SqlConnection.ClearPool and SqlConnection.ClearAllPools Method.

Resources