Black
Black

Reputation: 5367

Efficient caching strategy for DB entities with lookup by two fields

I have implemented a very simple lookup-cache in order to optimize processing of some DB entities. The cache class looks like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SyncEngine.Caches
{
    class TenantsCache : Cache
    {
       System.Collections.Generic.List<tenant> list;

        public override void ReadFromDB()
        {
            using (var ctx = new MyContext())
            {
                this.list = ctx.tenants.ToList<tenant>();
            }
        }

        public override void Add(object o)
        {
            list.Add((tenant)o);
        }

        public tenant LookupByFNandGID(string fn, int groupId)
        {
            tenant match = null;
            foreach (tenant t in list)
            {
                if (t.friendlyName == fn && t.groupId == groupId) // <-- slowest line
                {
                    match = t;
                    break;
                }
            }
            return match;
        }
    }
}

By analyzing CPU usage, I see that this Lookup (specifically the highlit line ) takes the most amount of processing time.

Is there a better, significantly more efficient way to implement this lookup/cache and/or the comparison here? Is there a more efficient in-built Collection with optimized lookup by two fields?

Upvotes: 0

Views: 86

Answers (1)

Kristof
Kristof

Reputation: 114

You can create Dictionary with a custom key that contains both fields:

class Key : IEquatable<Key>
{
    public string fn;
    public int groupId;

    public override bool Equals(object obj)
    {
        Key k = obj as Key;
        if (k == null)
        {
            return false;
        }
        else
        {
            return this.Equals(k);
        }
    }

    public bool Equals(Key other)
    {
        return this.fn == other.fn && this.groupId == other.groupId;
    }

    public override int GetHashCode()
    {
        return fn.GetHashCode() * 13 + groupId.GetHashCode();
    }
}

Then you can use a dictionary which is much faster for lookup than a list:

Dictionary<Key, tenant> foo = new Dictionary<Key, tenant>();

Upvotes: 3

Related Questions