views:

258

answers:

3
+7  A: 

Are you sure you don't want to try an Object Relational Mapper?

Maybe Linq to SQL or nHibernate?

Robert Harvey
+1 for leveraging someone else's hard work and not reinventing the wheel.
Soviut
In fact ADO.NET Entities is more of an ORM than Linq to SQL.
Scott Whitlock
A: 

I would spontaneously want to disconnect the database dependency from the objects a bit. You could start by creating an interface that defines the storage methods for your TestData object (in my example there is only the Add method, but this can of course be extended):

public interface ITestDataRepository
{
    void Add(TestData data);
}

Next step is to create your TestData class. One feature of that class could be to accept an ITestDataRepository as a parameter in the constructor, and to expose an Add method:

public class TestData
{
    public TestData(ITestDataRepository repository)
    {
        Repository = repository;
    }

    public ITestDataRepository Repository { get; private set; }

    public string SomeData { get; set; }

    public void Add()
    {
        if (Repository != null)
        {
            Repository.Add(this);
        }
    }
}

Last thing to do is to implement the data mechanism that you want to use. In this case OleDb, but it could just as well be Xml, SqlServer or any other form of data storage:

public class DbTestDataRepository : ITestDataRepository
{
    const string InsertionQuery = @"INSERT INTO TEST (TESTDATA) VALUES (?)";

    public void Add(TestData data)
    {

        using (OleDbConnection conn = DbUtil.GetConnection())
        using (OleDbCommand command = new OleDbCommand(InsertionQuery, conn))
        {
            command.Parameters.Add("@p1", OleDbType.BSTR).Value = data.SomeData;

            using (OleDbDataReader reader = command.ExecuteReader())
            {
                // perhaps log something?
            }
        }
    }

}

The above design provides a couple of different advantages over the design in your question:

  • There is no hard relation between your object model and the concrete storage implementation; you can change storage mechanism without altering the TestData object for instance.
  • It is testable; since the only requirement on the data storage mechanism is that it implements the repository interface, the data storage can easily be mocked, which makes unit testing easier.
  • In this concrete database code, the connection object lives only for a very short moment, which is usually the recommended way of doing it (the DbUtil.GetConnection method is something that I "invented"; it does not exist, but I usually like to centralize the code for setting up the connection, so I don't multiply it all over my code).

These are just some quick ideas (for instance, I did not test the code other than compiling it).

Fredrik Mörk
@Fredrik: I'm not sure I understand what you're getting at here. Maybe I didn't explain it properly, but I can already "change [the] storage mechanism without altering the TestData [class]". What I was trying to get at with this question was that I'd have a base class to provide common elements of data access, but also provide a DB class for each of my main object types, so that I can add/delete/modify them specific to their type. If I change the storage type, I'll have to refactor my code to the new system, but the same thing applies to your code as well, from what I can tell.
AgentConundrum
I apologize if I misunderstood what you were getting at with this. I'm using this project (this hobby project) to teach myself C# and some design, so I might be missing a lot from your answer.
AgentConundrum
I am not sure you misunderstood anything; that might as well be me :) I was not aware that you already had separated model classes, and that we only saw the underlying db classes here, so the design that I suggested here (on a conceptual level) might already be rather close to what you have.
Fredrik Mörk
I really could've explained it better. If it helps, imagine the AddTestData method as a GetEmployees method which returns List<Employee>.
AgentConundrum
+1  A: 

There are lots of ways of doing this, and the vast majority of OO folks will disagree with mine.

I suggest you take a more relational approach, and instead of having classes for tables, have classes for relations. In relational theory, the result of a query is a relation just like the relations that were used in the query; in fact you never see anything but results of queries, since even to get the contents of a table you need to SELECT * FROM x, which is applying the identity function to it.

So do your queries using the relational language you already have at your disposal (building up a framework to write the queries for you, if you need to go that far), and the results of queries should be your classes or, if you're not working in a language where it's easy to create new classes on the fly, some other sort of structure (such as objects). Then you simply use those results directly.

Curt Sampson