NibblyPig
NibblyPig

Reputation: 52942

Persisting data without a reference

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

Answers (2)

Matias Cicero
Matias Cicero

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

ΩmegaMan
ΩmegaMan

Reputation: 31616

In your situation a singleton (which supports DI) is a valid route to go.

Upvotes: 0

Related Questions