tags:

views:

58

answers:

2

I have a model that must be in one of the following mutually exclusive states: New, In Progress, or Closed.

The application allows a user to save a record and then retrieve them by providing a list of matching states.

I inherited an SQL database where the state is stored as an integer that represents bitwise flags. I have to call a procedure that does the matching with a bitwise operation:

CREATE PROCEDURE SearchByState
    @MatchingStates       int
AS
BEGIN
    SELECT Id, State
    FROM Records
    WHERE @MatchingStates & State > 0
END;
GO

This is all fine by me.

Now, in the C# implementation, it's pretty clear that I should define flags to represent a combination of matching states in a query:

[Flags]
public enum States
{
    None = 0x0,
    New= 0x1,
    InProgress = 0x2,
    Closed = 0x4,
    All = New | InProgress | Closed
}

The issue is that the model of the record must have a property that represents a single state.

The question is, what should be the type of the State property of the model of this record:

1) Just use the enumeration flags:

public class Record
{
    public int Id { get; set; }

    // Must ensure the value is equal to one of
    // States.New, States.InProgress, or States.Closed
    public States State { get; set; }
}

2) Define a new enum type for a mutually exclusive state:

public enum State
{
    New,
    InProgress,
    Closed
}

public class Record
{
    public int Id { get; set; }

    // Must be stored as the value of one of 
    // States.New, States.InProgress, or States.Closed
    public State State { get; set; }
}

The drawback of #1 is semantic: The States enumeration represents a combination of states, not a single state.

The drawback of #2 is practical: When storing the state, I have to determine the underlying value to be stored.

Can you think of a way to represent all of this while minimizing these disadvantages?

A: 

I would go with option #2 and then modify your Get/Set statements to determine the underlying value each time. This way it is done for you everytime you call the properties. Code it once, and you are done.

pattertj
+2  A: 

I would leave it as a single, non-flags enum.

When you pass this to your procedure, you can build the integer from the enum by using bitwise or (|), or even just add the values (cast to int). I would try to avoid "breaking" your logic in order to make a single legacy query work, and instead rework the code that calls the query to handle the unusual requirements there.

This keeps the code clean everywhere. "State" in your case should not be a flag enum - there is only one possible state.

Reed Copsey
Note also that the OP will need additional validation in their setter -- rather than using an auto-property -- if they want to enforce this. With the example code from the question there's nothing to stop me from doing something like `myRecord.State = (State)123456;`
LukeH
@LukeH: True, but that's true with any enum type, flag enum or not.
Reed Copsey