I have an extremely complicated relational database, which is causing me to use the same code over and over again. I'm trying to clean it up using a fairly sophisticated TableRow class, however I've came across one major problem. The best way I can explain what I'm trying to do is by some example code:
public abstract class TableRow
{
public abstract string TableName { get; }
public abstract string PrimaryKey { get; }
//there's a lot of these sort of methods for multi-to-multi links, links by two columns, etc
protected T GetLinkedRow<T>() where T : TableRow
{
//here I need to get TableName and PrimaryKey (without creating a new instance of T)
}
}
public class Person : TableRow
{
public override string TableName { get { return "People"; } }
public override string PrimaryKey { get { return "PersonID"; } }
}
public class Dog : TableRow
{
public override string TableName { get { return "Dogs"; } }
public override string PrimaryKey { get { return "DogID"; } }
public Person GetOwner() { return GetLinkedRow<Person>(); }
}
Now I realise this is not the way to go about what I'm trying to achieve, because I COULD make a class that has a variable value for TableName or PrimaryKey, but I'm not going to. I'd like to be able to override a static property, but I know this is not possible. I did previously have a class per table, but that meant there was 70 fairly useless classes and that's what I'm trying to avoid. What would be a better way to go around this sort of issue?
Update:
I eventually went with creating a new instance of T to get the TableName, as I will be initialising the new instance anyway. Although SLaks' solution is much better than this, it doesn't guarantee that the derived class has the TableName and PrimaryKey attributes. For the majority of people, SLaks' solution will be more appropriate, so I will mark that as the accepted answer.
protected T GetLinkedRow<T>() where T : TableRow, new()
{
T row = new T();
DbDataReader reader = ExecuteReader("SELECT * FROM [" + row.TableName + "] WHERE [" + this.PrimaryKey + "] = " + this.ID);
if(!reader.Read())
throw new Exception("No linked row found");
row.Load(reader);
return row;
}
//here's the reason I didn't really want to do this in the first place. Many-to-many relationship. quite messy
protected IEnumerable<T> GetLinkedRows<T>(string junctionTable) where T : TableRow, new()
{
T row = new T();
DbDataReader reader = ExecuteReader("SELECT * FROM [" + row.TableName + "] INNER JOIN [" + junctionTable + "] ON [" + row.TableName + "].[" + row.PrimaryKey + "] = [" + junctionTable + "].[" + row.PrimaryKey + "] WHERE [" + junctionTable + "].[" + this.PrimaryKey + "] = " + this.ID;
while(reader.Read()) {
row.Load(reader);
yield return row;
if(reader.HasRows)
row = new T();
}
}