Reputation: 52942
I have an a problem in C# where when I want to do a query to the database, I create a new instance of my DBQuerier()
and call a Run()
method on it.
The DBQuerier
can connect to one of several databases, depending on what is passed to the run method - for example new DBQuerier().Run(DBEnum.CatDatabase)
;
DBQuerier
is part of a library as a variety of solutions use it.
I have a configuration file that I can load and parse to get all of the connections loaded into memory, used for the enum lookup. However, I am unsure of how to persist this information. It looks like a job for dependency injection:
new DBQuerier(new MyConnectionStringLoader()).Run(...)
However I don't want it to load the file and parse it every single time a db query is run in this way. I can't store it within DBQuerier because this object is created and discarded every time.
If I make a ConnectionStringManager class, if it is static then I can't cleanly dependency inject MyConnectionStringLoader into it, and it makes it harder to unit test. If I make it a singleton I have some similar issues.
Is there a good solution for this problem? Googling it has revealed myriad of posts saying 'never use static classes or singleton' so I am pretty stuck.
Upvotes: 0
Views: 52
Reputation: 26281
It seems that DbQuerier
does exactly the same for any database. The only thing changing is the connection string.
I would do something like this:
public interface IDbQuerier
{
void Run();
}
public abstract class BaseDbQuerier : IDbQuerier
{
private static IDictionary<DbEnum, string> _connections;
static BaseDbQuerier()
{
_connections = // Load connection strings from configuration
}
protected abstract DbEnum Database { get; }
public void Run()
{
string connectionString = _connections[Database];
// DbQuerier logic
}
}
public enum DbEnum
{
CatDatabase,
DogDatabase,
TurtleDatabase
}
And then the different implementations:
public class CatDbQuerier : BaseDbQuerier
{
protected override DbEnum Database { get { return DbEnum.CatDatabase; } }
}
public class DogDbQuerier : BaseDbQuerier
{
protected override DbEnum Database { get { return DbEnum.DogDatabase; } }
}
public class TurtleDbQuerier : BaseDbQuerier
{
protected override DbEnum Database { get { return DbEnum.TurtleDatabase; } }
}
Having different implementations for each database will let you to easily inject it to any class that needs it, using a DI framework of your choice.
Upvotes: 2
Reputation: 31616
In your situation a singleton (which supports DI) is a valid route to go.
Upvotes: 0