CMS
CMS

Reputation: 3757

Query different columns depending on generic type argument

I have a table with configurations and there are multiple types (stored in different columns) and i need to query with entity framework for the current type based on the generic type

I have 2 approaches 1 is just casting everything to (dynamic), basically saying i don't need type checking here

and it look like this

   static TValue GetValueBasedOnType<TValue>(int configKey)
    {
        var query = dbcontext.Configurations.Where(c => c.configKey == configKey);
        if(typeof(TValue) == typeof(bool))
            return (dynamic)(query.Select(c => c.ValueBit).FirstOrDefault() ?? false);
        if(typeof(TValue) == typeof(string))
            return (dynamic)(query.Select(c => c.ValueText).FirstOrDefault());
        if (typeof(TValue) == typeof(decimal))
            return (dynamic)(query.Select(c => c.ValueDecimal).FirstOrDefault());
        return default(TValue);
    }

Or i can just cast the query to the current type, by first making it a general object and then change it back to the original type, like this

    static TValue GetValueBasedOnType<TValue>(int configKey)
    {
        var query = dbcontext.Configurations.Where(c => c.configKey == configKey);
        if (typeof(TValue) == typeof(bool))
            return (TValue)(object)(query.Select(c => c.ValueBit).FirstOrDefault() ?? false);
        if (typeof(TValue) == typeof(string))
            return (TValue)(object)(query.Select(c => c.ValueText).FirstOrDefault());
        if (typeof(TValue) == typeof(decimal))
            return (TValue)(object)(query.Select(c => c.ValueDecimal).FirstOrDefault());
        return default(TValue);
    }

I just wonder what option is a better idea to use?

Upvotes: 3

Views: 270

Answers (1)

Stephen Kennedy
Stephen Kennedy

Reputation: 21568

You can cast directly to TValue using the Linq Cast function:

static TValue GetValueBasedOnType<TValue>(int configKey)
{
    var query = new List<Configuration>{ new Configuration { ValueDecimal = 1.2M, ValueBit = true, ValueText = "Text" }};
    if (typeof(TValue) == typeof(bool))
        return query.Select(c => c.ValueBit).Cast<TValue>().FirstOrDefault();
    if (typeof(TValue) == typeof(string))
        return query.Select(c => c.ValueText).Cast<TValue>().FirstOrDefault();
    if (typeof(TValue) == typeof(decimal))
        return query.Select(c => c.ValueDecimal).Cast<TValue>().FirstOrDefault();
    return default(TValue);
}

As you can see, I used a List<Configuration> to test your function. With the following additional code in LinqPad:

public class Configuration
{
    public bool ValueBit { get; set; }
    public string ValueText { get; set; }
    public decimal ValueDecimal { get; set; }
}

void Main()
{
    GetValueBasedOnType<bool>(0).Dump();
    GetValueBasedOnType<string>(0).Dump();
    GetValueBasedOnType<decimal>(0).Dump();
}

my output is, as expected:

True Text 1.2

Out of interest I ran a similar query against a database of my own in Linqpad and again I got the expected result and the SQL generated was satisfactory - a TOP(1) query.

Upvotes: 1

Related Questions