6

If I want to restrict the values of the spicelevel column in the database to 1, 2 and 3, I could do something like

    private enum SpiceLevel
    {
        Low=1,
        Medium=2,
        Hot=3
    }

Then in the code I could do (int)SpiceLevel.Low to pick 1 as the spice level.

Now what if I have a need where I can only accept "Red Rose","White Rose" and "Black Rose" for the values of a column in the database? What is a graceful way to handle this?

I am thinking of storing them in a config file or constants, but neither is as graceful as enums. Any ideas?

Update:

The answer here worked for me

Community
  • 1
  • 1
Foo
  • 4,206
  • 10
  • 39
  • 54

4 Answers4

7

You can use a property for this

public string[] AllowedRoses = new string[] {  "Red Rose", "White Rose" ,"Black Rose" };
string _Rose = "Red Rose";
public string Rose
{
    get
    {
        return _Rose;
    }
    set
    {
        if (!AllowedRoses.Any(x => x == value)) 
               throw new ArgumentException("Not valid rose");
        _Rose = value;
    }
}
I4V
  • 34,891
  • 6
  • 67
  • 79
2

I can see the following options:

  • verify the value in the setter (see for example l4V's answer)

  • conceptually, you're thinking about an enum. So you could do the following:

enum RoseType { RedRose, WhiteRose, BlackRose };

and then provide appropriate conversion from this enum to string. Two convenient options how to do it are described here: Enum ToString with user friendly strings. One is to use a custom Description attribute, and the second (I'd prefer this one) to provide an extension method:

public static class RoseTypeExtensions
{
  public static string GetString(this RoseType @this)
  {
    switch (@this)
    {
      case RoseType.RedRose:
        return "Red Rose";
      case RoseType.WhiteRose:
        return "White Rose";
      case RoseType.BlackRose:
        return "Black Rose";
      default:
        throw new InvalidOperationException();
    }
  }
}
  • create a set of constants:
public class RoseType
{
  public readonly RoseType RedRose = new RoseType("Red Rose");
  public readonly RoseType WhiteRose = new RoseType("White Rose");
  public readonly RoseType BlackRose = new RoseType("Black Rose");

  public string Content { get; private set; }

  private RoseType(string content)
  {
    this.Content = content;
  }

  public override string ToString()
  {
    return this.Content;
  }
}

As Oskar Berggren correctly pointed out in the comment, RoseType should also provide other standard overrides beside ToString: Equals, GetHashCode, operator== and operator!=.

Community
  • 1
  • 1
BartoszKP
  • 34,786
  • 15
  • 102
  • 130
0

There is no really good solution. All of them require the database to be "synchronized" with the enum in C#.

Simplest solution:

What you said store the enum values as integers in the database.

Almost as simple but less efficient:

Store the values as strings in the database and convert between string and enum with anEnumVar.ToString() and Enum.Parse (or any of the other parse methods in Enum).

Complex but flexible:

Have a sort of enum in the database: a table with string values and ids and then use foreign keys to that table where you want to save the enums. This allows you to either select/update/insert using the numeric value or the string value (via a join).

It also maintains integrity as it is not possible to store an integer which has no corresponding enum value.

The downside is the complexity.

Eli Algranti
  • 8,707
  • 2
  • 42
  • 50
0

Create a mapping of string to enum with Dictionary<string, SpiceLevel> to associate the string to the Enum. Wrap them in a class.

You could also use a Decorator attribute [Name("Red Rose"] Low=1, and get that from the enum itself, but that involves reflection, which has some performance issues, especially when iterating through enum values to find the one with the matching attribute.

public static class Spice
{
    public enum Level
    {
        Low = 1,
        Medium = 2,
        Hot = 3
    }

    private static readonly Dictionary<string, Level> spices = new Dictionary<string, Level>{
        { "Red Rose", Level.Low },
        { "White Rose", Level.Medium },
        { "Black Rose", Level.Hot },
    };

    public static bool TryGet(string spiceName, out Level spiceLevel) => spices.TryGetValue(spiceName, out spiceLevel);

    public static string SpiceName(Level target) => Enum.GetName(typeof(Spice.Level), target);
}

/// <summary>
/// Some tests to validate it works. This could be a unit test or just in a console app
/// </summary>
public class SpiceTest
{
    public void VerifyBlackRoseIsHot()
    {
        string subject = "Black Rose";
        Spice.Level expectedSpice;

        // Here's the ease of use. Pass a string, get an enum and whether it's a valid string
        var result = Spice.TryGet(subject, out expectedSpice);

        //Some Assertion from a unit test library
        Assert.True(result, $"Unable to find spice '{subject}', when it should exist");
        Assert.True(Spice.Level.Hot.Equals(expectedSpice), $"The returned spice '{ Spice.SpiceName(expectedSpice) }' was not the value 'Hot' as expected");
    }
}
Antony Booth
  • 413
  • 4
  • 5