Search code examples
c#linqigroupingilookup

How to get value from IGrouping where key and value in object match


I have a database table with three columns: CodeType, Code, Name

I am holding the values in memory, a poor man's cache if you will with the values assigned to a Lookup.

public class ShortCodeCache
{
    public DateTime LastRefresh { get; set; }

    public Lookup<string, ShortCode> CodeList { get; set; }
}

public class ShortCode
{
    public string CodeType { get; set; }
    public string Code { get; set; }
    public string Name { get; set; }
}

I pull the values out of the DB and assign them to the Lookup.

private static void GetShortCodeCache(DateTime current)
{
    try
    {
        using (SqlConnection cn = new MSSqlServerConnection().GetConnection())
        {
            using (SqlCommand cmd = new SqlCommand())
            {
                cmd.CommandText = Query;
                cmd.Connection = cn;
                cn.Open();

                List<ShortCode> codesList = new List<ShortCode>();

                SqlDataReader readline = cmd.ExecuteReader();
                while (readline.Read())
                {
                    ShortCode shortCode = new ShortCode
                    {
                        CodeType = readline["CodeType"].ToString().Trim(),
                        Code = readline["Code"].ToString().Trim(),
                        Name = readline["Name"].ToString().Trim()
                    };

                    codesList.Add(shortCode);
                }

                currentCache.CodeList = (Lookup<string, ShortCode>)codesList.ToLookup(code => code.CodeType);

                if (currentCache.CodeList.Count != 0)
                    currentCache.LastRefresh = current;

                if (log.IsDebugEnabled)
                {
                    log.Debug("LastCacheRefresh: " + currentCache.LastRefresh);
                }
            }
        }
    }
    catch (SqlException sqlex)
    {
        log.Error(sqlex.Message);
        throw;
    }
    catch (Exception ex)
    {
        log.Error(ex.Message);
        throw;
    }
        
    return; 
}

I believe this portion up to here is working.

My problem is I am unable to get the Name for a specific CodeType and Code. For example, I pass in "DamageQuadrant" and "P9" and I need the Name value.

table view

This is what I currently have but VS is barking at me about no definition for CodeType.

public static string GetNameFromCode(string type, string code)
{
    CheckCodeCache();

    var codeType = currentCache.CodeList.Where(x => x.Key == type);
    string data = codeType.Where(x => x.CodeType, code).Name;

    return data;
}

I've tried various other ways including using an && condition in the Linq code. This looks like it would be easy but so far not.


Solution

  • First: you're forgetting to add your new ShortCodes to the codesList, so the current code isn't going to give you anything in your lookup.

    Second: use ILookup<> rather than Lookup<>. There's no good reason for you to specify the implementation type. If you are only expecting one possible item per combo, use an IDictionary<> instead.

    Third: don't use .Where() on a lookup or dictionary. Use [key] syntax instead.

    Fourth: key the lookup or dictionary on the values you want to look things up with.

    public IDictionary<(string Type, string Code), ShortCode> ShortCodesByTypeAndCode { get; set; }
    
    currentCache.ShortCodesByTypeAndCode = codesList.ToDictionary(code => (code.CodeType, code.Code));
    
    return currentCache.ShortCodesByTypeAndCode[(type, code)].Name;