Tip 23 – How to fake Enums in EF 4

As of right now Enums are not in EF4.

Now we will be listening to your feedback about Beta1, and making some adjustments, so you never know, but at the moment it doesn’t look like they will be supported.

Yesterday though I came up with a workaround that, while a bit of work, is pretty interesting.

Workaround

To get this working you need .NET 4.0 and you need to use POCO classes.

Imagine you have an Enum like this:

public enum Priority
{
   High,
   Medium,
   Low
}

First step is to create a ComplexType with just one property, something like this:

<ComplexType Name="PriorityWrapper" >
<Property Type="Int32" Name="Value" Nullable="false" />
</ComplexType>

Then if you want to have a property in an Entity that returns an Enum instead use the wrapping ComplexType.

As I said this only works in POCO. The reason is you need to do some interesting things in your PriorityWrapper complex type class:

public class PriorityWrapper
{
private Priority _t;
public int Value {
get {
return (int) _t;
}
set {
         _t = (Priority) value;
}
}
public Priority EnumValue
{
get {
return _t;
}
set {
_t = value;
}
}
}

Notice it has a Value property of type int just like the ComplexType definition, but it also has a way to set and get the Priority too via the EnumValue property.

Now we have this class we can use it in our POCO entities, so for example imagine you have a Task entity:

public class Task
{
public virtual int Id { get; set; }
public virtual PriorityWrapper Priority { get; set; }
public virtual string Title{ get; set;}
}

The next step is interesting, add some implicit conversion between PriorityWrapper and Priority:

public static implicit operator PriorityWrapper(Priority p)
{
return new PriorityWrapper { EnumValue = p };
}

public static implicit operator Priority(PriorityWrapper pw)
{
if (pw == null) return Priority.High;
else return pw.EnumValue;
}

With these implicit conversions in place you gain the illusion that the Priority property on the Task class is actually a Priority.

For example you can do this:

Task task = new Task {
Id = 5,
Priority = Priority.High,
Title = “Write Tip 23”
};

Rather than this needing to do this:

Task task = new Task {
Id = 5,
Priority = new PriorityWrapper {EnumValue = Priority.High },
Title = “Write Tip 23”
};

And this:

if (task.Priority == Priority.High)

Rather than this:

if (task.Priority.EnumValue == Priority.High)

But what about queries?

You can even use this enum in queries:

var highPriority =
from task in ctx.Task
where task.Priority.Value == (int) Priority.High
select task;

Cool huh?

Now this is not as good as if we natively supported enums, but it is not that far off, especially from the perspective of someone programming against your entities.

Enjoy.

This is 23rd post in my ongoing series of Entity Framework Tips.