I'm designing a WCF Service that will called by several hundred clients, and I have a question about the best architecture for the classes that will run by database queries. Today I only access SQL Server, so I have a static class that I call internally that does all the dirty work of creating connections and datareaders. Below is a simple example:
namespace DBHelper.Utility
{
public static class SqlDBManager
{
public static void RunSql(String pSql, DBParamsHelper pDBParams, String pConnStringConfigName)
{
String sConnectionString = GetConnectionStringFromConfig(pConnStringConfigName);
SqlConnection oConn = new SqlConnectionsConnectionString
oConn.Open();
try
{
SqlCommand oCommand = new SqlCommand(pSql, oConn);
oCommand.CommandTimeout = 0;
if (pDBManagerParams != null)
{
foreach (SqlParameter sqlParam in pDBManagerParams)
{
oCommand.Parameters.Add(sqlParam);
}
}
oCommand.ExecuteNonQuery();
}
finally
{
oConn.Close();
}
}
}
}
Now, I need to add support for running both Sql Server and Oracle. My initial idea was to declare an interface, and have my existing SqlDBManager implement it, and then develop an OracleDBManager implementing the same interface. The problem is that my class is static, and static classes cannot implement an interface. I would like my helper class to remain as static, with it's a lot more practical, and I don't have to create a new object every time I need to run a query. I also thought of using class inheritance, but I can't have statis virtual methods, so not much use there. I considered some singleton implementations so I wouldn't have to create classes, but then I would have trouble on the multi-threaded access.
What would be the best design pattern so I can have great performance on multiple threaded scenario (very important), not too much work coding for productivity (not have to create a lot of classes), and have a standard methods for both OracleDBManager and SqlDBManager classes? The standard method is very important, because I don't want to the code that uses these helper classes to know if they are connected to Oracle or Sql Server.
I did consider using ORM solution, such as Entity Framework 4 and nHibernate, but the performance impact was too much. Since I will run simple queries, the query syntax difference between PL-SQL and TSQL won't matter.
Any input and idea will be greatly appreciated. Tks
Why not make your static method private, wrap the classes in an interface to support MS-SQL / Oracle, and call the private static methods in the respective interfaces?
E.g:
public interface ISqlDbManager
{
void SaveOrder(Order o);
void FindOrderById(int orderId);
}
public class SqlServerDbManager : ISqlDbManager
{
private static void RunSql(String pSql, DBParamsHelper pDBParams, String pConnStringConfigName)
{
// implement as you did above
}
public void FindOrderById(int orderId)
{
// create SQL, call private "RunSql" method.
}
}
Do the same thing for the other implementation (OracleDbManager).
It makes sense to have it private, since the consumer shouldn't care how the underlying persistence mechanism works.
And this will also make unit testing easier - create a "MockDbManager" class, where the private static method does basic LINQ operations on an in-memory list.
On a side note, i would strongly recommend the use of stored procedures, instead of constructing sql commands manually. Better for query plan caching / optimization.
The interface is the right direction to go in, but as you've pointed out, you can't have a static class implement an interface. I understand wanting to minimize the fuss of object creation, but that will likely be necessary in some way in order to have two different database classes.
The solution I suggest is multi-faceted. First is an interface with a signature similar to what you listed above:
public Interface IDbManager {
void RunSql(String pSql, DBParamsHelper pDBParams, String pConnStringConfigName)
}
That can be implemented in SQL- and Oracle-specific versions, you already have the SQL version, just make it non-static and implement the interface.
Now try a database factory, perhaps like the following:
public static class DbFactory {
public static IDbManager CreateDb(DbType type) {
select (type) {
case DbType.Sql:
return new SqlDbManager();
break;
case DbType.Sql:
return new OracleDbManager();
break;
}
}
}
Then you should be able to do something like:
var db = DbFactory.CreateDb(DbType.Sql);
db.RunQuery(...);
This code is untested, but hopefully you get the idea. I use a similar solution for one of my projects where I need to get data from different data stores. The strategy and factory patterns ease this process.
Hope that helps!
Related
I have an app that collects data and writes it to a database. The database type is not known in advance, it's defined via an .ini file. So I have a method like this, if the database is Firebird SQL:
public bool writeToDB()
{
FbConnection dbConn = new FbConnection(connString);
dbConn.Open();
FbTransaction dbTrans = dbConn.BeginTransaction();
FbCommand writeCmd = new FbCommand(cmdText, dbConn, dbTrans);
/* some stuff */
writeCmd.ExecuteNonQuery();
dbTrans.Commit();
writeCmd.Dispose();
dbConn.Close();
return true;
}
To make the same work for e.g. MS Access database, I only have to replace FbConnection, FbTransaction and FbCommand with OleDbConnection, OleDbTransaction and OleDbCommand respectively.
But I don't want to have a separate identical method for each type of database.
Is it possible to define the database connection / transaction / command type at runtime, after the database type is known?
Thanks
When you're writing code at this level - opening and closing connections, creating and executing commands - there's probably no benefit in trying to make this method or class database-agnostic. This code is about implementation details so it makes sense that it would be specific to an implementation like a particular database.
But I don't want to have a separate identical method for each type of database.
You're almost certainly better off having separate code for separate implementations. If you try to write code that accommodates multiple implementations it will be complicated. Then another implementation (database) comes along which almost but doesn't quite fit the pattern you've created and you have to make it even more complicated to fit that one in.
I don't know the specifics of what you're building, but "what if I need a different database" is usually a "what if" that never happens. When we try to write one piece of code that satisfies requirements we don't actually have, it becomes complex and brittle. Then real requirements come along and they're harder to meet because our code is tied in knots to do things it doesn't really need to do.
That doesn't mean that all of our code should be coupled to a specific implementation, like a database. We just have to find a level of abstraction that's good enough. Does our application need to interact with a database to save and retrieve data? A common abstraction for that is a repository. In C# we could define an interface like this:
public interface IFooRepository
{
Task<Foo> GetFoo(Guid fooId);
Task Save(Foo foo);
}
Then we can create separate implementations for different databases if and when we need them. Code that depends on IFooRepository won't be coupled to any of those implementations, and those implementations won't be coupled to each other.
First (and Second and Third). STOP REINVENTING THE WHEEL.
https://learn.microsoft.com/en-us/ef/core/providers/?tabs=dotnet-core-cli
Alot of code and an alot of better testing has already been done.
Guess what is in that larger list:
FirebirdSql.EntityFrameworkCore.Firebird Firebird 3.0 onwards
EntityFrameworkCore.Jet Microsoft Access files
......
So I'm gonna suggest something in lines with everyone else. BUT also... allows for some reuse.
I am basing this .. on the fact the Entity Framework Core...provides functionality to several RDBMS.
See:
https://learn.microsoft.com/en-us/ef/core/providers/?tabs=dotnet-core-cli
public interface IEmployeeDomainDataLayer
{
Task<Employee> GetSingle(Guid empKey);
Task Save(Employee emp);
}
public abstract class EmployeeEntityFrameworkDomainDataLayerBase : IEmployeeDomainDataLayer
{
/* you'll inject a MyDbContext into this class */
//implement Task<Employee> GetSingle(Guid empKey); /* but also allow this to be overrideable */
//implement Task Save(Employee emp); /* but also allow this to be overrideable */
}
public class EmployeeJetEntityFrameworkDomainDataLayer : EmployeeEntityFrameworkDomainDataLayerBase, IEmployeeDomainDataLayer
{
/* do not do any overriding OR override if you get into a jam */
}
public class EmployeeSqlServerEntityFrameworkDomainDataLayer : EmployeeEntityFrameworkDomainDataLayerBase, IEmployeeDomainDataLayer
{
/* do not do any overriding OR override if you get into a jam */
}
You "code to an interface, not an implementation". Aka, your business layer codes to IEmployeeDomainDataLayer.
This gives you most code in EmployeeEntityFrameworkDomainDataLayerBase. BUT if any of the concretes give you trouble, you have a way to code something up ONLY FOR THAT CONCRETE.
If you want DESIGN TIME "picking of the RDBMS", then you do this:
You inject one of the concretes ( EmployeeJetEntityFrameworkDomainDataLayer OR EmployeeSqlServerEntityFrameworkDomainDataLayer ) into your IOC, based on which backend you want to wire to.
If you want RUN-TIME "picking of the RDMBS", you can define a "factory".
public static class HardCodedEmployeeDomainDataLayerFactory
{
public static IEmployeeDomainDataLayer getAnIEmployeeDomainDataLayer(string key)
{
return new EmployeeJetEntityFrameworkDomainDataLayer();
// OR (based on key)
return new EmployeeSqlServerEntityFrameworkDomainDataLayer();
}
}
The factory above suffers from IOC anemia. Aka, if your concretes need items for their constructors..you have to fudge them.
A better idea of the above is the kissing cousin of "Factory" pattern, called the Strategy Design.
It is a "kinda factory", BUT you inject the possible results of the "factory" in via a constructor. Aka, the "factory" is NOT hard coded...and does NOT suffer from IOC anemia.
See my answer here:
Using a Strategy and Factory Pattern with Dependency Injection
I'm prepering for my final exam with C# WPF using MVVM creating an query editor which needs to support multiple database motors, and wondering what's the best practice of having multiple database connection types to switch between in a view.
This includes having etc. oracle, mssql, mysql connections.
I thought of two scenarios to do this which is:
A) Create a new instance of a database connection, where it creates a new view window to display so the user can work for that specifik connection.
B) Make a global access list to switch between connections by written command. etc. 'change database to xxxx', for the current view they are displaying.
What i'm searching for, is scenario B), so it's more flexible for the user. I'm so far being guided to read about dependency injection and inheritance, where it delegating from abstract baseclass to resolve this.
The second thing is how to access this list afterwards in the command field, find the name of a database based on the database name written, and change the connection type for the (this) current view they are displaying. But, this needs to be unique due we cannot hard-code the connection type in any viewModels.
Currently i'm guided using DataServices, with MVVMLight nuget, where it's created one per connection type. Here i store the connection in one list:
public class MySqlService : IMySqlService
{
private List<MySqlConnection> Connections = new List<MySqlConnection>();
public MySqlConnection AddConnection(string hostName, string userName, string userPassword, string dataBase)
{
var connectionString = $"Server={hostName};database={dataBase};user id={userName};password={userPassword};";
var mySqlCon = new MySqlConnection(connectionString);
if(mySqlCon.State == ConnectionState.Closed)
{
mySqlCon.Open();
Connections.Add(mySqlCon);
return mySqlCon;
}
else
{
return null;
}
}
Result case
I've found an described response on Stack.Exchange site which has below response, in case it gets removed:
Short:
What you want is multiple implementations for the interface that your application uses.
like so:
public interface IDatabase
{
void SaveToDatabase();
void ReadFromDatabase();
}
public class MySQLDatabase : IDatabase
{
public MySQLDatabase ()
{
//init stuff
}
public void SaveToDatabase(){
//MySql implementation
}
public void ReadFromDatabase(){
//MySql implementation
}
}
public class SQLLiteDatabase : IDatabase
{
public SQLLiteDatabase ()
{
//init stuff
}
public void SaveToDatabase(){
//SQLLite implementation
}
public void ReadFromDatabase(){
//SQLLite implementation
}
}
//Application
public class Foo {
public IDatabase db = GetDatabase();
public void SaveData(){
db.SaveToDatabase();
}
private IDatabase GetDatabase()
{
if(/*some way to tell if should use MySql*/)
return new MySQLDatabase();
else if(/*some way to tell if should use MySql*/)
return new SQLLiteDatabase();
throw new Exception("You forgot to configure the database!");
}
}
As far as a better way of setting up the correct IDatabase implementation at run time in your application, you should look into things like "Factory Method", and "Dependancy Injection".
Long:
This question, especially in the database context, has been asked too many times. Here I will try to thoroughly show you the benefit of using abstraction (using interfaces) to make your application less coupled and more versatile.
Before reading further, I recommend you to read and get a basic understanding of Dependency injection, if you do not know it yet. You might also want to check the Adapter design pattern, which is basically what hiding implementation details behind interface's public methods means.
Dependency injection, coupled with Factory design pattern, is the foundation stone and an easy way to code the Strategy design pattern, which is a part of IoC principle.
Don't call us, we will call you. (AKA the Hollywood principle).
Decoupling an application using abstraction
1. Making the abstraction layer
You create an interface - or abstract class, if you are coding in a language like C++ - and add generic methods to this interface. Because both interfaces and abstract classes have the behaviour of you not being able to use them directly, but you have to either implement (in case of interface) or extend (in case of abstract class) them, the code itself already suggests, you will need to have specific implementations to fullfil the contract given by either the interface or the abstract class.
Your (very simple example) database interface might look like this (the DatabaseResult or DbQuery classes respectively would be your own implementations representing database operations):
public interface Database
{
DatabaseResult DoQuery(DbQuery query);
void BeginTransaction();
void RollbackTransaction();
void CommitTransaction();
bool IsInTransaction();
}
Because this is an interface, it itself does not really do anything. So you need a class to implement this interface.
public class MyMySQLDatabase : Database
{
private readonly CSharpMySQLDriver _mySQLDriver;
public MyMySQLDatabase(CSharpMySQLDriver mySQLDriver)
{
_mySQLDriver = mySQLDriver;
}
public DatabaseResult DoQuery(DbQuery query)
{
// This is a place where you will use _mySQLDriver to handle the DbQuery
}
public void BeginTransaction()
{
// This is a place where you will use _mySQLDriver to begin transaction
}
public void RollbackTransaction()
{
// This is a place where you will use _mySQLDriver to rollback transaction
}
public void CommitTransaction()
{
// This is a place where you will use _mySQLDriver to commit transaction
}
public bool IsInTransaction()
{
// This is a place where you will use _mySQLDriver to check, whether you are in a transaction
}
}
Now you have a class which implements the Database, the interface just became useful.
2. Using the abstraction layer
Somewhere in your application, you have a method, let's call the method SecretMethod, just for fun, and inside this method you have to use the database, because you want to fetch some data.
Now you have an interface, which you cannot create directly (uh, how do I use it then), but you have a class MyMySQLDatabase, which may be constructed using the new keyword.
GREAT! I want to use a database, so I will use the MyMySQLDatabase.
Your method might look like this:
public void SecretMethod()
{
var database = new MyMySQLDatabase(new CSharpMySQLDriver());
// you will use the database here, which has the DoQuery,
// BeginTransaction, RollbackTransaction and CommitTransaction methods
}
This is not good. You are directly creating a class inside this method, and if you are doing it inside the SecretMethod, it is safe to assume you would be doing the same in 30 other methods. If you wanted to change the MyMySQLDatabase to a different class, such as MyPostgreSQLDatabase, you would have to change it in all your 30 methods.
Another problem is, if the creation of MyMySQLDatabase failed, the method would never finish and therefore would be invalid.
We start by refactoring the creation of the MyMySQLDatabase by passing it as a parameter to the method (this is called dependency injection).
public void SecretMethod(MyMySQLDatabase database)
{
// use the database here
}
This solves you the problem, that the MyMySQLDatabase object could never be created. Because the SecretMethod expects a valid MyMySQLDatabase object, if something happened and the object would never be passed to it, the method would never run. And that is totally fine.
In some applications this might be enough. You may be satisfied, but let's refactor it to be even better.
The purpose of another refactoring
You can see, right now the SecretMethod uses a MyMySQLDatabase object. Let's assume you moved from MySQL to MSSQL. You do not really feel like changing all the logic inside your SecretMethod, a method which calls a BeginTransaction and CommitTransaction methods on the database variable passed as a parameter, so you create a new class MyMSSQLDatabase, which will also have the BeginTransaction and CommitTransaction methods.
Then you go ahead and change the declaration of SecretMethod to the following.
public void SecretMethod(MyMSSQLDatabase database)
{
// use the database here
}
And because the classes MyMSSQLDatabase and MyMySQLDatabase have the same methods, you do not need to change anything else and it will still work.
Oh wait!
You have a Database interface, which the MyMySQLDatabase implements, you also have the MyMSSQLDatabase class, which has exactly the same methods as MyMySQLDatabase, perhaps the MSSQL driver could also implement the Database interface, so you add it to the definition.
public class MyMSSQLDatabase : Database { }
But what if I, in the future, don't want to use the MyMSSQLDatabase anymore, because I switched to PostgreSQL? I would have to, again, replace the definition of the SecretMethod?
Yes, you would. And that does not sound right. Right now we know, that MyMSSQLDatabase and MyMySQLDatabase have the same methods and both implement the Database interface. So you refactor the SecretMethod to look like this.
public void SecretMethod(Database database)
{
// use the database here
}
Notice, how the SecretMethod no longer knows, whether you are using MySQL, MSSQL or PotgreSQL. It knows it uses a database, but does not care about the specific implementation.
Now if you wanted to create your new database driver, for PostgreSQL for example, you won't need to change the SecretMethod at all. You will make a MyPostgreSQLDatabase, make it implement the Database interface and once you are done coding the PostgreSQL driver and it works, you will create its instance and inject it into the SecretMethod.
3. Obtaining the desired implementation of Database
You still have to decide, before calling the SecretMethod, which implementation of the Database interface you want (whether it is MySQL, MSSQL or PostgreSQL). For this, you can use the factory design pattern.
public class DatabaseFactory
{
private Config _config;
public DatabaseFactory(Config config)
{
_config = config;
}
public Database getDatabase()
{
var databaseType = _config.GetDatabaseType();
Database database = null;
switch (databaseType)
{
case DatabaseEnum.MySQL:
database = new MyMySQLDatabase(new CSharpMySQLDriver());
break;
case DatabaseEnum.MSSQL:
database = new MyMSSQLDatabase(new CSharpMSSQLDriver());
break;
case DatabaseEnum.PostgreSQL:
database = new MyPostgreSQLDatabase(new CSharpPostgreSQLDriver());
break;
default:
throw new DatabaseDriverNotImplementedException();
break;
}
return database;
}
}
The factory, as you can see, knows which database type to use from a config file (again, the Config class may be your own implementation).
Ideally, you will have the DatabaseFactory inside your dependency injection container. Your process then may look like this.
public class ProcessWhichCallsTheSecretMethod
{
private DIContainer _di;
private ClassWithSecretMethod _secret;
public ProcessWhichCallsTheSecretMethod(DIContainer di, ClassWithSecretMethod secret)
{
_di = di;
_secret = secret;
}
public void TheProcessMethod()
{
Database database = _di.Factories.DatabaseFactory.getDatabase();
_secret.SecretMethod(database);
}
}
Look, how nowhere in the process you are creating a specific database type. Not only that, you aren't creating anything at all. You are calling a GetDatabase method on the DatabaseFactory object stored inside your dependency injection container (the _di variable), a method, which will return you the correct instance of Database interface, based on your configuration.
If, after 3 weeks of using PostgreSQL, you want to go back to MySQL, you open a single configuration file and change the value of DatabaseDriver field from DatabaseEnum.PostgreSQL to DatabaseEnum.MySQL. And you are done. Suddenly the rest of your application correctly uses the MySQL again, by changing one single line.
Best practice is that you simply don't dynamically change database type.
In real world apps you don't really dynamically change between oracle and sql server or mysql. Your data is in a given database and that's where it's staying. It's a big deal changing to another one and that will necessitate porting data, staff learning the new rdbms, quite possibly rewriting swathes of stored procedures.
Some software packages are intended to support multiple different rdbms but this is a one off decision that is taken prior to install.
One client has sql server and that's what they want to use. Another client has Oracle so that's what they expect to use.
There are exceptions, of course.
A client might want your small system to be installed locally and keep costs down by using a free rdbms like sql express.
One off install choices are often supported.
When designing such a system it is usual to try and minimise what needs to be switched out.
This is not always possible.
For simple systems it can sometimes be "just" a matter of a connection string to change and this is handled by config file.
Others have more complicated requirements and the tendency then is to encapsulate within stored procedures if possible. That way your code can remain the same but Oracle has a stored procedure which does oracle specific stuff and the sql server database has a stored procedure does sql server specific stuff. This means writing, testing and optimising stored procedures for each option. Which is costly and far from ideal. There is an "up" side though. If the client company has a DBA, they can potentially tweak your stored procedures for performance.
In the projects I worked on I have classes that query/update database, like this one,
public class CompanyInfoManager
{
public List<string> GetCompanyNames()
{
//Query database and return list of company names
}
}
as I keep creating more and more classes of this sort, I realize that maybe I should make this type of class static. By doing so the obvious benefit is avoid the need to create class instances every time I need to query the database. But since for the static class, there is only one copy of the class, will this result in hundreds of requests contend for only one copy of static class?
Thanks,
I would not make that class static but instead would use dependency injection and pass in needed resources to that class. This way you can create a mock repository (that implements the IRepository interface) to test with. If you make the class static and don't pass in your repository then it is very difficult to test since you can't control what the static class is connecting to.
Note: The code below is a rough example and is only intended to convey the point, not necessarily compile and execute.
public interface IRepository
{
public DataSet ExecuteQuery(string aQuery);
//Other methods to interact with the DB (such as update or insert) are defined here.
}
public class CompanyInfoManager
{
private IRepository theRepository;
public CompanyInfoManager(IRepository aRepository)
{
//A repository is required so that we always know what
//we are talking to.
theRepository = aRepository;
}
public List<string> GetCompanyNames()
{
//Query database and return list of company names
string query = "SELECT * FROM COMPANIES";
DataSet results = theRepository.ExecuteQuery(query);
//Process the results...
return listOfNames;
}
}
To test CompanyInfoManager:
//Class to test CompanyInfoManager
public class MockRepository : IRepository
{
//This method will always return a known value.
public DataSet ExecuteQuery(string aQuery)
{
DataSet returnResults = new DataSet();
//Fill the data set with known values...
return returnResults;
}
}
//This will always contain known values that you can test.
IList<string> names = new CompanyInfoManager(new MockRepository()).GetCompanyNames();
I didn't want to ramble on about dependency injection. Misko Hevery's blog goes into great detail with a great post to get started.
It depends. Will you ever need to make your program multithreaded? Will you ever need to connect to more than one database? Will you ever need to store state in this class? Do you need to control the lifetime of your connections? Will you need data caching in the future? If you answer yes to any of these, a static class will make things awkward.
My personal advice would be to make it an instance as this is more OO and would give you flexibility you might need in the future.
You have to be careful making this class static. In a web app, each request is handled on its own thread. Static utilities can be thread-unsafe if you are not careful. And if that happens you are not going to be happy.
I would highly recommend you follow the DAO pattern. Use a tool like Spring to make this easy for you. All you have to do is configure a datasource and your DB access and transactions will be a breeze.
If you go for a static class you will have to design it such that its largely stateless. The usual tactic is to create a base class with common data access functions and then derive them in specific classes for, say, loading Customers.
If object creation is actually the overhead in the entire operation, then you could also look at pooling pre-created objects. However, I highly doubt this is the case.
You might find that a lot of your common data access code could be made into static methods, but a static class for all data access seems like the design is lost somewhere.
Static classes don't have any issues with multi-threaded access per-se, but obviously locks and static or shared state is problematic.
By making the class static, you would have a hard time unit testing it, as then you
would probably have to manage internally the reading of the connection string in a non-clear manner, either by reading it inside the class from a configuration file or requesting it from some class that manages these constants. I'd rather instantiate such a class in a traditional way
var manager = new CompanyInfoManager(string connectionString /*...and possible other dependencies too*/)
and then assign it to a global/public static variable, if that makes sense for the class, ie
//this can be accessed globally
public static CompanyInfoManager = manager;
so now you would not sacrifice any flexibility for your unit tests, since all of the class's dependencies are passed to it through its constructor
I have some code which forms a database-centric class which performs CRUD operation. Insert() and Select() methods use the same connection string. At the moment, both methods are repetitive by repeating the standard bit of setting up a SqlConnection.
How best should this be refactored? Should I have a property for SqlConnection?
Thanks
Pull all your DB operations out into a single class, and pass the class to the objects that need it. You can do this via constructor injection (each new object gets an IDBProvider passed to it which it then uses for database operations).
Something like this:
public interface IDBProvider {
// ... list of DB operations you care about
List<Products> GetProducts(string vendor)
}
public class SomeWorkerClass {
private IDBProvider dbConnection;
public SomeWorkerClass(IDBProvider dbProvider) {
dbConnection = dbProvider;
}
public void SomeFunction() {
List<Products> = dbConnection.GetProducts("test");
}
}
There are lots of frameworks that do this kind of stuff for you, like NHibernate, but in some cases its just as easy to roll your own (upgrading existing code, organizations that dont want external framework dependencies, etc).
I usually do it one of two ways.
A class that contains static methods and properties to connect to a database. I can then use it in any other class I need.
A SqlConnection property in a class that connects to databases. I then inject the connection from the controlling class when I need it.
By far the first option is used most frequently. The only issue is that if the database server changes, I need to recompile the class. We only have one database server, though, and it doesn't change that often, so it really isn't that much of an issue.
The good thing about the second option is that it's a lot more flexible; if the server, user, or password changes it's as simple as updating that information in the controlling class.
This depends on your application. As far as I'm concerned: No. You might want to add a new method to set up the connection (that might even be a good idea), but a connection as field/property sounds like "I open a connection for the whole lifetime of my form", which is evil in my world.
Create a helper method and write something like
using (var connection = CreateSqlConnection()) {
// Do the operations here
}
we are making an ASP.Net application. We would like to have our application to be at least sorta DB agnostic, most notable to be compatible with both SQL Server and PostgreSQL. What is the best way of doing this? What are some of the common pitfalls? Also is there a class or something that already abstracts away the difference between things like SqlConnection and whatever PostgreSQL uses for connections?
(We are wanting to be DB agnostic so we can use PostgreSQL here(in development and later in our own hosting) due to price and let our self-hosting clients use Sql Server if they so wish)
All ADO.Net providers extend the basic interfaces:
IDbConnection
IDbTransaction
IDbCommand
IDataReader
IDbDataParameter
So in theory you can write your whole DAL (Data Access Layer) against the abstract interfaces and leverage any provider, including 3rd party ones like MySQLs. In practice, no mortal ever managed to pull this trick. The interfaces are very hard to program against on one hand, and any application beyond a demo-ware will quickly run into the wall of SQL dialects incompatibility.
A more feasable approach is to settle for a number of target destinations and develope specific DALs. Entity Framework and repository pattern and nHibernate and all such help, but none solves the fundamental issues.
You could use Entity Framework. That way you would have a single programming model to work against.
http://msdn.microsoft.com/en-us/library/aa697427(VS.80).aspx
http://www.devart.com/dotconnect/postgresql/
If you just want to use ADO.NET directly, you can use the DbProviderFactory to abstract away the provider (SqlClient, OleDb etc) that you are using. Usually you use this in conjunction with the <connectionStrings> configuration element, with code something like:
ConnectionStringSettings c = ConfigurationManager.ConnectionStrings[name];
DbProviderFactory factory = DbProviderFactories.GetFactory(c.ProviderName)
...
IDbConnection connection = _factory.CreateConnection();
connection.ConnectionString = c.ConnectionString;
...
There's lots of info in MSDN.
Of course this doesn't help you with differences in SQL syntax between different providers - you need a lowest common denominator approach to work with multiple providers. This affects things like the syntax for parameters (e.g. # prefix for SQL Server, positional parameters only for OleDb, ...).
I just create an interface for my data source and then implement it for each data source type I need to use. Normally they look something like this:
public interface IMyProjectDataSource
{
IEnumerable<string> GetUserNames();
void AddUser(string userName);
}
public class SqlServerMyProjectDataSource : IMyProjectDataSource
{
public SqlServerMyProjectDataSource(string connectionString)
{
//...
}
public IEnumerable<string> GetUserNames()
{
//...
}
public void AddUser(string userName)
{
//...
}
}
public class PostgreSqlMyProjectDataSource : IMyProjectDataSource
{
public IEnumerable<string> GetUserNames()
{
//...
}
public void AddUser(string userName)
{
//...
}
}
public class HttpCacheSqlMyProjectDataSource : IMyProjectDataSource
{
public HttpCacheSqlMyProjectDataSource(IMyProjectDataSource parentMyProjectDataSource)
{
}
public IEnumerable<string> GetUserNames()
{
//...
}
public void AddUser(string userName)
{
//...
}
}
I also like this because it allows you to "chain" them together. For instance you can do all of your data source caching like this:
public class HttpCacheSqlMyProjectDataSource : IMyProjectDataSource
{
public HttpCacheSqlMyProjectDataSource(IMyProjectDataSource parentMyProjectDataSource)
{
//...
}
public IEnumerable<string> GetUserNames()
{
//...
}
public void AddUser(string userName)
{
//...
}
}
The hardest part is deciding how to create it, especially if you're planning to chain more than one together. For that I generally store it in my Global.asax.cs as a singleton and create it from a type name in the .config file. You can use Type.GetType() and then Activator.CreateInstance() to do that and most of the chaining I have will be done no matter what the data source in the .config is so I don't have to worry about creating some sort of "constructor" type or a complicated .config.
Hopefully that makes sense. This may not be the best for all situations but I have had a lot of luck with it.
Entity Framework is an option as mentioned by Shiraz. You might also consider other ORM solutions such as NHibernate.
I would recommend to go with some sort of Repository Pattern.
It's not a silver bullet that will save you from hacking for each DBMS flavour, but that is the way to go if you want it to be maintainable from the beginning, something that ORMs just do not provide.
http://blog.wekeroad.com/2008/04/07/asp-net-mvc-mvc-storefront-part-2
At a very high level you would want to use something that abstracts your database more than just the SqlConnection, SqlCommand, and Sql* classes. So when people say to use ORMs, they're pretty much right. The ORMs provide that level of abstraction for you.
But for abstracting away SqlCommand and SqlConnection there are interfaces in the System.Data namespace. IDbConnection, IDbCommand, etc. are already inside the framework and you can code against those. The issue then is finding kind of way to create the concrete classes and you can tackle that using an IoC container or a provider pattern.
The best solution for database-agnostic applications is usually an ORM (this tag). There are plenty of them for .NET - this question will give you some guidance on which one to choose.
The three most popular ones are:
NHibernate
Linq-to-SQL (now superceded by Entity Framework) - used by Stackoverflow.com. SQL Server only
Subsonic