Question

I'm in the middle of making a short program that uses Databases. Most of my tables have a class that represents them and usually, I access the rows in this table by Id. So I thought I'd be nifty and created this base class for my classes, thinking that I'd be able to standardize my approach. I made this:

public abstract class Loadable<T> where T: Loadable<T>, new()
{
    protected abstract static List<T> loaded { get; set;}
    protected abstract static string tableName { get; set; }
    protected abstract void setData(DataRow data);
    public abstract int id { get; set; }
    public static T getById(int id)
    {
        if (loaded.Any((g) => g.id == id))
            return (T)loaded.First((g) => g.id == id);

        T ret = new T();
        ret.setData(SQLiteDB.main.getRowById(tableName, id));
        T.
        return ret;
    }
}

When I finished, I tried compiling with a smug sense of satisfaction just to learn that abstract static is not a thing. Standard rookie mistake. Not to mention that the

T.loaded.Add(ret);

line is just plain embarrasing.

While I can probably bit the bullet and implement this method in every class, I'm wondering what cool patterns you guys can come up with. I've looked into some, but they mostly require implementation in the derived classes.

The key aspects of the algorithm involve:

  • Each Item Loaded only once.
  • List "loaded" is populated when a new item is loaded
  • Implementation is kept to a minimum - In this case it was just "loaded" and "tableName"(setData was already required).
  • SQLite is not really the focus, the idea is to only perform heavy loads once.

Is this possible, or just a pipe dream?

Edit:

I might have ommited that I would like each Class to have their own static dictionary of instances.(The reason for the abstract static)

The entire point, I guess, is looking for a way to enforce static variables in derived classes.

Was it helpful?

Solution

I don't see why all of that has to be protected or abstract. Here's a simple example that, I think, achieves your goal. It does reflection on the inherited class to find a static "TableName" property which the base class caches for lookups. Another option would be to use an attribute on the inherited class, but you are going to need reflection either way. If the TableName is not defined an exception is thrown. Also, I used ConcurrentDictionary for faster, thread-safe look up of the instances.

public abstract class Loadable<T> where T: Loadable<T>, new()
{
    private readonly static ConcurrentDictionary<int, T> _cache = new ConcurrentDictionary<int, T>();

    private readonly static Func<int, T> _addDelegate = key => {
        T item = new T();
        item.SetData(SQLiteDB.main.getRowById(_tableName, key));
        return item;
    };

    private static readonly string _tableName;

    static Loadable()
    {
        var prop = typeof(T).GetProperty("TableName", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);
        if (prop == null)
            throw new NotSupportedException(string.Format("Type '{0}' does not support TableName", typeof(T)));

        _tableName = (string)prop.GetValue(null);
    }

    protected abstract void SetData(DataRow data);

    public virtual int Id { get; set; }

    public static T GetById(int id)
    {
        return _cache.GetOrAdd(id, _addDelegate);
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top