3

I am wrestling with this OOP design issue. Take these base classes, for example:

class Database
{
    public string ConnectionString { get; set; }
    public Table MyTable { get; set; }
}

class Table
{
    public string Name { get; set; }
}

This example is oversimplified to just concentrate on the question at hand.

If I wanted to add logic that would get the Table row count, you would think that naturally belongs in Table class:

class Table
{
    public string Name { get; set; }

    public int GetRowCount() { ... }
}

The problem is, in order to get the row count, a database connection would need to happen. Not a big deal, but the Table class has no way to retrieve the Database.ConnectionString property in order to actually connect to get the row count of the particular table.

I see a few options here, and none of them really seem like great approaches.

Keep logic out of child objects

In this case, the GetRowCount() logic would have to live in the parent object. Something like this:

class Database
{
    public string ConnectionString { get; set; }
    public Table MyTable { get; set; }

    public int GetRowCount(Table table) { ... }
}

class Table
{
    public string Name { get; set; }
}

The Table class is now "dumb" to the logic of the row count, which isn't altogether a bad thing, but now there is no way to have a member in the Table class to store or retrieve data that is directly related to the Table class.

Have a reference to the Parent Object in the Child object

This I like even less than the above approach. In this case, it would resemble something like this:

class Database
{
    public string ConnectionString { get; set; }
    public Table MyTable { get; set; }
}

class Table
{
    public string Name { get; set; }
    public Database Parent { get; set; }

    public int GetRowCount() { ... }
}

Sure, Table.GetRowCount() can make a reference to Table.Parent.ConnectionString, but this just seems like unnecessary recursion and... sloppy.

Explicity pass the required data around

I don't like this either, but if the Table.GetRowCount() implementation required that the connection string is passed to it, this logic could live in the Table class, but now there is a lack of DRY as well as a leak of Database data into the Table implementation:

class Database
{
    public string ConnectionString { get; set; }
    public Table MyTable { get; set; }
}

class Table
{
    public string Name { get; set; }

    public int GetRowCount(string connectionString) { ... }
}

Not to mention that this could lead to challenging logic bugs, I would imagine.

How is this typically done, and what's the best approach here? I want the row count logic to live where it naturally belongs, with the Table class. But that logic and data depends on a member (the connection string) that naturally lives in the Database class.

1

3 Answers 3

6

Pass an already established connection to Table's constructor (as opossed to the other answer suggestion of passing the connection string).

That's the approach I've used for years. Objects that access the database don't open or close database connections. A connection is made by some other component, usually the main class, and passed to the constructors of the classes that need access to the database.

A further benefit of that approach is that you decouple the code using the conecction from the code creating it. For example, there could be several versions of the database driver, or there could be a connection pool, and the children classes whould work all the same.

0

Pass a reference to the ConnectionString (or better yet, the actual Connection) to the Table's constructor.

Since the Table is already inside the Database (and doesn't really belong anywhere else), the Database can simply give it the magic string during construction, and then the Table always has what it needs to execute the row count logic. Since your Connection(String) is mutable, you can't get away with a copy, but giving the Table a reference to that one connection is much better than giving it a reference to the whole Database object or forcing the Database to contain all the real code.

0

It is perfectly fine for a child object to have a reference to its parent. There is no unnecessary recursion and no sloppiness. Naturally, that would be a construction-time parameter, and it would be stored in a readonly member, so there would be no set.

Then, the table could obtain the connection string from the database object, if it really needed to.

However, I would recommend that you don't do what you are trying to do. It is none of the table's business to obtain a connection string and establish a connection in order to get a count. The fact that a connection string is involved is an implementation detail. The entire concept of connection strings is a hack which is best encapsulated in the smallest amount of code which is absolutely necessary to get the job done.

So, either always work with a separate connection object which has already been created (presumably using a connection string) or, better yet, make your database be the connection object, fully encapsulating the fact that its establishment involved a useful hack known as a connection string.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.