UPDATE! There’s a June CTP with new support for enums!
If you have an entity with an enumeration and you wan’t to store it using Entity framework 4, Code-only, you might run into problem. The convention-based mapping is sufficent for generating the schema but you will run into problem when trying to create an objectset.
The solution that I will present here is kind of simple: Make a custom-type that you map as a complex-type using ComplexTypeConfiguration, then you implement implicit operator overloading to provide implicit-conversion between this custom-type and the enumeration.
The Entity
public class Tifi : ICamyinEntity
{
public Guid Id { get; set; }
public byte[] Version { get; set; }
public TifiType Type { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Source { get; set; }
}
The Enumeration
public enum TifiTypes : int
{
Undefined = 0,
Blog = 1,
Video = 2
}
The Custom-type
public class TifiType
{
public int Value { get; private set; }
private TifiType()
: this(default(TifiTypes))
{}
public TifiType(int value)
{
Value = value;
}
public TifiType(TifiTypes type)
{
Value = (int)type;
}
public static implicit operator int(TifiType type)
{
return type.Value;
}
public static implicit operator TifiType(int value)
{
return new TifiType(value);
}
public static implicit operator TifiTypes(TifiType type)
{
return (TifiTypes)type.Value;
}
public static implicit operator TifiType(TifiTypes type)
{
return new TifiType(type);
}
}
The Mappings
public class TifiTypeMapping : ComplexTypeConfiguration<TifiType>, ICamyinMapping
{
public TifiTypeMapping()
{
Property(o => o.Value);
}
}
public class TifiMapping : EntityConfiguration<Tifi>, ICamyinMapping
{
public TifiMapping()
{
HasKey(o => o.Id);
Property(o => o.Id)
.StoreGeneratedPattern = StoreGeneratedPattern.Identity;
Property(o => o.Version)
.IsConcurrencyToken()
.IsRequired()
.HasStoreType("timestamp")
.StoreGeneratedPattern = StoreGeneratedPattern.Computed;
Property(o => o.Source)
.HasMaxLength(200)
.IsUnicode()
.IsRequired();
Property(o => o.Title)
.HasMaxLength(100)
.IsUnicode();
Property(o => o.Description)
.HasMaxLength(1000)
.IsUnicode()
.IsOptional();
}
}
That’s it. You will now be able to assign enumeration values to an instance of Tifi and it’s member Type.
var tifi = new Tifi
{
Title = "My first Tifi",
Description = "This works",
Source = "http://daniel.wertheim.se",
Type = TifiTypes.Blog
};
//Daniel
I’ve been using the string equivalent of this for a while now – the implementation is good and it means there won’t be much effort required to refactor once EF supports enums (EF12?).
One point that might be worth noting is that you have to writes LINQ to Entities queries in a very specific way:
var statusString = MyStatusEnum.Active.ToString();
return enrolments.Where(x => x.Status.Value == statusString);
This code will not work:
return enrolments.Where(x => x.Status.Value == MyStatusEnum.Active);
That’s correct. You will have to use the
Type.Valueproperty in your queries. I would not compare it against the string, but instead the int representation. But that’s my opinion//Daniel
Hi Daniel,
I get a unable to cast exception, when i do something like this
var tifies = context.Tifies.where(t => t.Type == (int)TifiTypes.Blog).ToList();
Am i doing it incorrectly?
Thanks
Guru
Please ignore my previous question. I was just being stupid by missing the t.Type.Value
However, I want to store TifiTypes in a lookup table (for reporting purposes). And how can I add a foreign key on Type column pointing to the PK of the look up table using EF code first?
Much appreciated.
Thanks
Guru
Thanks for the article.
I’ve been using ServiceResponse (Previous bits from core module) to get all result as well as any violations along with status code in the client. I see some changes in this release. I think you adopted IScenarioResponse and IScenarioRequest.
Now I need to implement IScenarioRequest for any validation even string[] ???
With ServiceResponse previous versions used “Try” action for executing data access layer. With new method how do you call similar functionality?
Also in ServiceResponse I used to get all result as well as any violations along with status code but with new thing I forced to create a new class (for violations as well as result). Or am I doing something wrong here? Any code samples for the service layer to share?
Thanks for the article, it’s just what I needed.
Did I get it right that TifiMapping class doesn’t map TifiType explicitly? Will it’s ComplexTypeConfiguration be automatically picked up by EF4 or not?
Hi,
The complex typemapping of TifiType is enough, you don’t have to explicitly map it in TifiMapping. EF will pick this up.
Note! I haven’t tested this with their latest release of the CTP 4 (http://www.microsoft.com/downloads/details.aspx?FamilyID=4e094902-aeff-4ee2-a12d-5881d4b0dd3e&displayLang=en)
//Daniel
I tried it with EF 4.1 and it works like a charm
One thing I did is decorating the class TifiType with [ComplexType] which in turn enabled me to remove the mapping TifiTypeMapping
Thanks
Nice update, thanks.
//Daniel
I added the property “Name” that returns the name of the enum as a string
public class TifiType
{
public int Value { get; private set; }
public string Name { get { return Enum.GetName(typeof(TifiTypes), Value); } }
//—- The rest of the code
}
Why not:
public class Tifi : ICamyinEntity
{
public Guid Id { get; set; }
public int Type { get; set; }
[NotMapped]
public TifiTypes TifiType{
get {return (TifiTypes)Type;}
set {Type = (int)value;}
}
public string Title { get; set; }
public string Description { get; set; }
public string Source { get; set; }
}
…
var tifi = new Tifi
{
Title = “My first Tifi”,
Description = “This works”,
Source = “http://daniel.wertheim.se”,
TifiType = TifiTypes.Blog
};
or I missing something?
Thanks for the comment and suggestion. Haven’t tested that but I guess you have and it’s cleaner seen to mappings but not to the model. Also it’s been a while since I wrote this and I don’t know what was supported when I tried it out.
//Daniel
This was a superb article, thank you.
Though, since I wish to only implement the code once I have tried to make this a generic type that takes my enumtype as type in, ie public class EnumType but unfortunately that kind of implementation was not supported by EF 4.1.
Instead I tried to make this a baseclass but ran into difficulties once again. Is there really no way to minimize the lines of code and still make this work?
I myself has tried to reuse mappings in earlier CTPs without any luck using inheritance and interfaces.
//Daniel
Pingback: SisoDb vs Entity Framework 4.1 Code first – Inserts « Daniel Wertheim
I am aware, that there has been an update to EF, so that it now supports Enums. On the ADO.NET team blog, there is walkthrough, explaining the use of Enums with ModelFirst/Database first tools (http://blogs.msdn.com/b/adonet/archive/2011/06/30/walkthrough-enums-june-ctp.aspx).
What I need to learn, is how to implement it it via Code First. Does anyone here have any information about that?
The only problem for me is that I have to work on a legacy database that allows the field (type) to be null. This is the error I get:
“The ‘Value’ property on ‘DocumentTypeWrapper’ could not be set to a ‘null’ value. You must set this property to a non-null value of type ‘Int32′.”
Do you have any idea to how I can make it allow to be null? Or at lease how I can map the null value from the database to a default enum?
Hi,
I guess you could do something like this:
using System; namespace ConsoleApplication4 { class Program { static void Main(string[] args) { var t1 = new TifiType(null); Console.WriteLine((TifiTypes)t1); //Writes Undefined var t2 = new TifiType(1); Console.WriteLine((TifiTypes)t2); //Writes Blog Console.WriteLine(((TifiType)TifiTypes.Video).Value); //Writes 2 Console.ReadKey(); } } public enum TifiTypes : int { Undefined = 0, Blog = 1, Video = 2 } public class TifiType { public int? Value { get; private set; } private TifiType() : this(default(TifiTypes)) { } public TifiType(int? value) { Value = value; } public TifiType(TifiTypes type) { Value = (int)type; } public static implicit operator int(TifiType type) { return type.Value ?? 0; } public static implicit operator TifiType(int value) { return new TifiType(value); } public static implicit operator TifiTypes(TifiType type) { return (TifiTypes)(type.Value ?? 0); } public static implicit operator TifiType(TifiTypes type) { return new TifiType(type); } } }Any idea how to do this in Model-first or Database-First approach?
I just figured out. I create a partial class of the complex type where I added the implicit operators.
thanks a bunch!