GetSchema("Databases") on ODBC connection (C#) - c#

I am testing various DB connection methods in C#. In particular, I am testing SqlConnection and OdbcConnection classes; my DB is SQLServer Express (.\SQLEXPRESS). Both are working reasonably well, except in listing available databases on the server.
In my test code I use a "generic" DbConnection object and a simple factory to create an instance of specific SqlConnetion and OdbcConnetion subclasses (they both derive from DbConnection):
DbConnection connection;
switch (connection_type)
{
case DbConnectionType.DBCONN_MSSQL:
connection = new SqlConnection(...sql connection string...);
break;
case DbConnectionType.DBCONN_ODBC:
connection = new OdbcConnection(...odbc connection string...);
break;
}
The trick seems to work well except when I try to get the list of databases on the server:
DataTable databases = connection.GetSchema("Databases");
foreach (DataRow database in databases.Rows)
{
String databaseName = database["database_name"] as String;
Console.WriteLine(databaseName);
}
When "connection" is an OdbcConnection (and, note, the database is the same), I get an exception saying that "Databases" key was not found. I listed all the keys exposed by GetSchema(), and the ODBC version returns only a subset of the items exposed by the SQLServer version. I couldn't find any hint about this specific problem. Is it a documented/expected behaviour? Am I doing something wrong?
NOTE: here how I build the ODBC connection string:
OdbcConnectionStringBuilder builder;
builder = new OdbcConnectionStringBuilder();
builder.Driver = "SQL Server";
builder.Add("Server", ".\\SQLEXPRESS");
builder.Add("Uid", "");
builder.Add("Pwd", ""); // Using current user
builder.Add("Integrated Security", "SSPI");
connection = new OdbcConnection(builder.ConnectionString);

Is it a documented/expected behaviour?
Yes. See Retrieving Database Schema Information
Am I doing something wrong?
If your goal is to read SQL Server metadata in a provider-agnostic way, then yes. You should query the SQL Server catalog views directly. sys.databases, sys.tables, etc.

Make sure your "Databases" model has a valid Key. Add the [Key] Data annotation if the key you want to implement for that database doesn't follow the "ClassName"+"ID" entity framework rule.

Related

how to properly create a postgres database connection class in c#?

I am new to working with databases.I am using postgres database.I want to connect it to c# for my project.Since I have multiple form screen in my project, I assume it is better to create a seperate database connection class instead of using the same code in every other classes.I want to learn how to create an effective postgres database connection class in c#
There's no need to create a connection class since database connections and commands aren't complicated or expensive to create. The best practice is to create a connection and command, execute the SQL, and then dispose of both of them. The typical pattern is:
string connString = {connection string from config};
using (OdbcConnection conn = new OdbcConnection(connString)) {
using(OdbcCommand cmd = new OdbcCommand(sql, conn) {
// execute command
}
}
The using construct ensures that the connection and command are closed een if there is a database error.
Take a look at this website: https://www.connectionstrings.com/postgresql/
This is a great resource for finding connection strings to a variety of different databases! I reference it quite a bit. There are a couple of different connection strings for postgreSql, so you will need to dtermine which one is best to use for your use case.
I wouldn't set up a special class for a connection. Instead I recommend that you use an appsettings.json or web.config file to store the connection string and call it when you need it. Check out the documentation from Microsoft: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-6.0

Is it possible to connect to SQL Server without specifying a database?

I'm trying to write some unit tests for my code that connect to SQL Server for persistence, but I would like to be able to run my unit tests by just pointing it at a SQL Server instance, and let the tests create their own database to run tests in, so after each test it can just drop the database and then on setup before the next test recreate it, so I know there is no legacy data or structures left over from a previous test effecting the next test.
In brief: no, you cannot do that. You might be able to leave out the database from the connection string, but in that case, that connection will be made to the configured default database of the login that's connecting to SQL Server (and that default database must exist at the time the connection is made)
If you want to have this scenario, you need to
first connect to your instance and database master and create your new testdb (or whatever it's called)
disconnect
in your tests, connect to the instance and the testdb database
Better yet: use a mocking framework of some sort so you don't even need an actual database in your testing scenario!
I use the following class to facilitate the OP's scenario:
public class MsSqlDatabaseCreator
{
public void Create(string connectionstring)
{
if (DatabaseExists(connectionstring))
{
DropDatabase(connectionstring);
}
CreateDatabase(connectionstring);
}
private static void CreateDatabase(string connectionString)
{
var sqlConnectionStringBuilder = new SqlConnectionStringBuilder(connectionString);
var databaseName = sqlConnectionStringBuilder.InitialCatalog;
sqlConnectionStringBuilder.InitialCatalog = "master";
using (var sqlConnection = new SqlConnection(sqlConnectionStringBuilder.ConnectionString))
{
sqlConnection.Open();
using (var sqlCommand = sqlConnection.CreateCommand())
{
sqlCommand.CommandText = $"CREATE DATABASE {databaseName}";
sqlCommand.ExecuteNonQuery();
}
}
}
private static bool DatabaseExists(string connectionString)
{
var sqlConnectionStringBuilder = new SqlConnectionStringBuilder(connectionString);
var databaseName = sqlConnectionStringBuilder.InitialCatalog;
sqlConnectionStringBuilder.InitialCatalog = "master";
using (var sqlConnection = new SqlConnection(sqlConnectionStringBuilder.ConnectionString))
{
sqlConnection.Open();
using (var command = sqlConnection.CreateCommand())
{
command.CommandText = $"SELECT db_id('{databaseName}')";
return command.ExecuteScalar() != DBNull.Value;
}
}
}
private static void DropDatabase(string connectionString)
{
var sqlConnectionStringBuilder = new SqlConnectionStringBuilder(connectionString);
var databaseName = sqlConnectionStringBuilder.InitialCatalog;
sqlConnectionStringBuilder.InitialCatalog = "master";
using (var sqlConnection = new SqlConnection(sqlConnectionStringBuilder.ConnectionString))
{
sqlConnection.Open();
using (var sqlCommand = sqlConnection.CreateCommand())
{
sqlCommand.CommandText = $#"
ALTER DATABASE {databaseName} SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
DROP DATABASE [{databaseName}]
";
sqlCommand.ExecuteNonQuery();
}
}
}
}
The important part is the switching of the database name (initial catalog) to master. This way you can have just one connectionstring.
What you want to accomplish is possible using a mocking framework, in which case you don't even have to "connect to a database", you simply mock the return values that the database should return in order for you to test your "db handler" implementation.
There are several to choose from when it comes to C#, I can recommend Rhino Mocks and Moq to name two. Here's a question detailing a bit more; https://stackoverflow.com/questions/37359/what-c-sharp-mocking-framework-to-use
Why not have the same named database dedicated for tests? and drop-create it every time. This way you won't need to mess about with connection strings - it is always the same.
And yet, there is a better solution: within all your tests, start transaction, do your test, where your data is messed up. Once you verified (or failed) the test, unroll the transaction. This way you don't need to drop-create your tests for every test, because the data is never changed.
But you'll need to make sure schema in test-database is always up to date. So you'll need to drop-create test database whenever your schema is changed.
I've blogged about database tests and how we deal with Entity Framework migrations. This might not be completely applicable to your situation, but might help with ideas.
Regarding using mocks in your tests - yes this is absolutely valid suggestion and should be followed most of the time. Unless you are trying to test the database layer. In that case no mocks will save you, and you just have to go to DB. Many times over I have tried to mock DbContext in EF, but never managed to simulate realistic DB behavior. So going to DB was easier for me, rather than simulating DB-mock.
I'd use SQL Server Management Objects for the task. It's Server and Database APIs doesn't necessarily need a connection string but I think you might still need to specify a database. You can use master for that. (Check jeroenh's answer about creating object using SMO API as well)
By the way, if you are using .Net 4.0.2 and up you can use LocalDB as well, which is even better.
Edit: Note that actually LocalDB is an SQL Server 2012 feature however you still need .Net Framework > 4.0.2 to be able to use it.

linq to entities changing database connection string in code

I am using the devart component dotconnect for postgresql. I have created the site using linq to entities, however, I would like each user to have a seperate database. This means that I need to change the connection string for each person that has logged in. I understand the main part of how to generate a new connection string etc, however, when i pass that as a paramater to the object context object it comes back with the error
"user id keyword not supported, "
if i create a class that generates an entity connection the error message changes to:
"Unable to load the specified metadata resource."
Cannot work out what I have done wrong in these instances.
ok so, as usual, when i posted this question, about 3 minutes later i found the problem. The entity connection string, for general purposes should have a cool little
res://*/
this makes the metadata work. This solves the problem of metadata resource and this works. So to help others who may, like me, have spent development time doing this, i created a class, with a method like so.
public static string getConnString(string database)
{
string connectionstring = "User Id=USER ID HERE;Password=PASSWORD HERE;Host=server;Database="+database+";Persist Security Info=True;Schema=public";
EntityConnectionStringBuilder newconnstring = new EntityConnectionStringBuilder();
newconnstring.Metadata = #"res://*/";
newconnstring.Provider = "Devart.Data.PostgreSql";
newconnstring.ProviderConnectionString = connectionstring;
return newconnstring.ToString();
}
then create a constructor like so
dataEntities data = new dataEntities(databaseConnection.getConnString(INSERTDBNAMEHERE);
Then we can reference that in the same way as a usual linq statement. Simples!!

How to change the database - Schema used by Entity Framework (mysql database)?

I use EntityFramework in a project to connect to a Mysql database. The provider is Devart Dot.connect.
This application needs to connect to a database using connexion parameters given by the user at runtime. This includes of course the Mysql Database name.
I used the EntityConnectionStringBuiler and EntityConnection classes to build-up and store the custom connexion parameters.
The problem is that even with such given parameters, the application always connect to the database named when designing the EntityModel using the visual studio wizard.
What is very strange is that when debuging and checking the status of the ObjectContext, the custom connexion parameters are correctly used...
It makes me mad !!!!!
Any clue ?
After spending one day on this issue, I finally came to understand that the problem was coming from the model.edmx file.
In this file, you have one line per EntitySet.
On each EntitySet element there is an attribute called schema. In case of SQL Server this attribute is set to the related table schema :
EntitySet Name="annee_civile"
EntityType="openemisModel.Store.annee_civile"
store:Type="Tables" Schema="mydatabase" />
If you provide the name of the Schema when constructiong you own EntityConnection, it seem that there is a conflict and that finally, the Schema defined in the edmx file will be used even if you specified another one in the connection parameters.
The solution is simply to remove the name of the schema in the edmx file.
THIS WORKS FOR MYSQL, probably not when connecting to a SQL server.
EntitySet Name="annee_civile"
EntityType="openemisModel.Store.annee_civile"
store:Type="Tables" Schema="" />
The EntityConnectionStringBuilder :
string providedString = "User Id=xxxx;Password=xxx;Host=xxxx;Database=anydatabasename";
EntityConnectionStringBuilder entityConnBuilder = new EntityConnectionStringBuilder();
entityConnBuilder.Provider = "Devart.Data.MySql";
entityConnBuilder.Metadata = #"res:///OpenEmisModel.csdl|res:///OpenEmisModel.ssdl|res://*/OpenEmisModel.msl";
entityConnBuilder.ProviderConnectionString = providedString;
The EntityConnection and the object context using it:
EntityConnection entityConnexionEmis = new EntityConnection(entityConnBuilder.ConnectionString);
objectcontextEntities testingContext = new objectcontextEntities(entityConnexionEmis);
The software is now able to connect to any database name.
Hope this helps.
Reference the dll Devart.Data.MySql.Entity.EF6.dll in the project.
Somewhere when your application is starting up and before database operations take place, add the following:
var config = MySqlEntityProviderConfig.Instance;
config.Workarounds.IgnoreSchemaName = true;
You will need to reference:
using Devart.Data.MySql.Entity.Configuration;

Getting a DataSet from an SQL Express Server C#

How can I get a DataSet with all the data from a SQL Express server using C#?
Thanks
edit: To clarify, I do want all the data from every table. The reason for this, is that it is a relatively small database. Previously I'd been storing all three tables in an XML file using DataSet's abilities. However, I want to migrate it to a database.
You can use the GetSchema method to get all the tables in the database and then use a data adapter to fill a dataset. Something like this (I don't know if it compiles, I just paste some code and change it a bit):
DbProviderFactory factory = DbProviderFactories.GetFactory("System.Data.SqlClient");
DataTable tables = null;
DataSet database = new DataSet();
using (DbConnection connection = factory.CreateConnection())
{
connection.ConnectionString = "Data Source=(local);Initial Catalog=Northwind;Integrated Security=True";
string[] restrictions = new string[4];
// Catalog
restrictions[0] = "Northwind";
// Owner
restrictions[1] = "dbo";
// Table - We want all, so null
restrictions[2] = null;
// Table Type - Only tables and not views
restrictions[3] = "BASE TABLE";
connection.Open();
// Here is my list of tables
tables = connection.GetSchema("Tables", restrictions);
// fill the dataset with the table data
foreach (DataRow table in tables.Rows)
{
string tableName = table["TABLE_NAME"].ToString();
DbDataAdapter adapter = factory.CreateDataAdapter();
DbCommand command = factory.CreateCommand();
command.Connection = connection;
command.CommandType = CommandType.Text;
command.CommandText = "select * from [" + tableName + "]";
adapter.SelectCommand = command;
adapter.Fill(database, tableName);
}
}
EDIT:
Now I refactored it a bit and now it's working as it should. The use of DbConnection and DbProviderFactories is for database engine abstraction, I recommend using it so you can change the database engine changing this line and the connection string:
DbProviderFactory factory = DbProviderFactories.GetFactory("System.Data.OracleClient");
The GetSchema method will retrive all tables from your database to a DataTable and then we get all the data from each table to the DataSet using the DataAdapter.
I think you need to narrow down the question somewhat... All the data? You mean, all the data in every table in every database? Well, the only answer to that is, a lot of code.
To connect to and talk to a SQL Server Express database engine, use the classes in the System.Data.SqlClient namespace, namely:
SqlConnection: Connect to the database
SqlCommand: Talk to the database
SqlDataReader: Iterate over data retrieved from the database
You can check the MSDN pages for all of these classes by clicking on the links above.
Here are some overview-links with more information:
CodeProject: Beginners guide to accessing SQL Server through C#
DevHood: Accessing SQL Server Data in C# with ADO.NET
Note that by and large, you use a SQL Server Express database engine the same way as the full SQL Server product, the difference is more in the tools you get with it, and some limitations in the express engine. Other than that you can just use the classes and language that you would use for a normal SQL Server database engine installation.
If this post didn't answer your question, please elaborate, and you have a higher chance of getting the answer you seek.
This can be done by using dataAdapter class.

Categories

Resources