Question

Is there a way to cache the results of a MySQL query, specifically a data-reader?

I have some mundane queries that really only need to be performed once when the application is loaded, then each form can use the cache values instead of querying the remote server.

At present my method is to use MySqlDataReader to retrieve the data and store it in another MySqlDataReader so I can retrieve it at a later time (example below)

if (parentfrm.prioritylist != null)
        {
            if (parentfrm.prioritylist.HasRows)
            {
                using (var rows = parentfrm.prioritylist)
                {
                    while (rows.Read())
                    {
                        cboxitem cbi = new cboxitem(int.Parse(rows["priorityid"].ToString()), rows["label"].ToString());
                        cb.Items.Add(cbi);
                    }
                }
            }
            else
            {
                query = @"SELECT priorityid, label FROM prioritylist WHERE active = 'Y' ORDER BY theorder ASC";
                parentfrm.prioritylist = db.localfetchrows(query);
                if (cb != null)
                {
                    using (var rows = db.localfetchrows(query))
                    {
                        while (rows.Read())
                        {
                            cboxitem cbi = new cboxitem(int.Parse(rows["priorityid"].ToString()), rows["label"].ToString());
                            cb.Items.Add(cbi);
                        }
                    }
                }
            }
        }
        else
        {
            query = @"SELECT priorityid, label FROM prioritylist WHERE active = 'Y' ORDER BY theorder ASC";
            parentfrm.prioritylist = db.localfetchrows(query);
            if (cb != null)
            {
                using (var rows = db.localfetchrows(query))
                {
                    while (rows.Read())
                    {
                        cboxitem cbi = new cboxitem(int.Parse(rows["priorityid"].ToString()), rows["label"].ToString());
                        cb.Items.Add(cbi);
                    }
                }
            }
        }
Was it helpful?

Solution

public class Priority{
    public int PriorityId {get;set;}
    public string Label {get;set;}
}

public class CachedItems {
    private static List<Priority> _priorityList=new List<Priority>();

    public static List<Priority> GetPriorityList() {
        if (_priorityList==null){
             // Load DB Items to the _priorityList, 
             // if the app is multithreaded, you might wanna add some locks here
        }
    }
}

Then anywhere in the code, just use CachedItems.GetPriorityList() to access the cached list.

OTHER TIPS

Short answer: populate an object, and reuse it

Longer answer: design your application to use some kind of decoupling. The simplest way is to work with the dual DataSet/DataAdapter classes + some databindings.

Not only your code will be simpler to read (and write), but you will have far more flexibility (like firing requests only as needed).

A traditional approach is to create :

  • a Data Abstraction layer (DAL) that wrap the DB operations to return Dataset (or custom classes), save changes (DataSet has a builtin change tracking feature)
  • A Business Logic Layer (BLL) that encapsulate the logic. The Bll can work with DALs
  • a UI layer, that contains the application itself. The Ui should only call BLL's method.

Start by reading this article : http://www.codeproject.com/Articles/36847/Three-Layer-Architecture-in-C-NET

A quick way is to use the dynamic Type/anonymous classes (.NET 4) which is on par with what you are already doing (building on Mennans code a bit)

    public class CachedItems
    {
        private static List<dynamic> _priorityList = new List<dynamic>();

        public static List<dynamic> GetPriorityList()
        {
            if (_priorityList == null)
            {
                // Load DB Items to the _priorityList, 
                // if the app is multithreaded, you might wanna add some locks here

                query = @"SELECT priorityid, label FROM prioritylist WHERE active = 'Y' ORDER BY theorder ASC";
                parentfrm.prioritylist = db.localfetchrows(query);
                if (cb != null)
                {
                    using (var rows = db.localfetchrows(query))
                    {
                        while (rows.Read())
                        {
                            _priorityList.Add(new { 
                                                PriorityId = int.Parse(rows["priorityid"].ToString()), 
                                                Label = rows["label"].ToString() 
                                              });
                        }
                    }
                }

            }

            return _priorityList;
        }
    }

Using the cached values:

        foreach (var item in CachedItems.GetPriorityList())
        {
            if (item.Priority == 1)
            {

            }
        }

What you don't get is type safety i.e. the item.Priority migth cause you runtime errors if Priority does not contain a value or a value which is not an int, you will have to cover this when loading the cache, but that is basically the situation you are in right now with the datareader.

You might consider a small application toolkit class, PriorityCheckboxes, and make it a singleton. Then when you need those checkbox values, first reference of the GetInstance() method on PriorityCheckboxes, should load it up. If you have a race condition with this, the load logic could go in a static initializer.

public class PriorityCheckboxes {
    private static CheckBox _CBItems = null;

    private static PriorityCheckboxes _instance - null;

    public CheckBox CheckBoxes { 
        get() { return _CBItems; } 
    }

    private PriorytyCheckboxes() {
        this.LoadCBItems();
        _instance = new PriorityCheckboxes();
    }

    public static PriorityCheckboxes GetInstance() { 
        if(_instance == null ) _instance = new PriorityCheckboxes();
        return _instance;
    }
    private void LoadCBItems() { }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top