Geeks With Blogs

@JReuben1
  • JReuben1 AngularJS Directive templateUrl --> halfway to W3C WebComponents ! about 555 days ago
  • JReuben1 Yeoman AngularJS generator - generate controllers, views, routes, services - NICE! about 557 days ago
  • JReuben1 A comparison of HTML5 Canvas 2D JS libs http://t.co/fcB7jvnhqY KineticJS , EaselJS, fabric.js, Paper.js, processing.js seen as the leaders about 557 days ago

Josh Reuben
This afternoon I Built a mechanism for mapping Enums to Lookup Tables in EF Code First - using complex types and implicit operators. The steps are as follows:
 
Step 1 – the Enum
 

// Avoid 0 values – SQL INT default value

 
    public enum JobInstanceStateEnum : int
    {
        Ok = 1,
        MissingResources = 2,
        DataFailure = 3,
        Aborted = 4
    }

 

 
Step 2 – the POCO for generating the Lookup Table
 

// As we are using id as FK, and it must match the enum, overide convention of identity keygen

 
    public class JobInstanceStateLookup
    {
        [DatabaseGenerated(DatabaseGenerationOption.None)]
        public int JobInstanceStateLookupId { getset; }
        public string Value { getset; }
    }

 

 
Step 3 – the POCO for generating the Entity Table

// Entity

 
    public class JobInstance
    {
        public int JobInstanceId { getset; }  // convention PK      
        public JobInstanceState Status { getset; } // enum ComplexType mapper
        public string blah { getset; }
    }

 

 
Step 4 – the ComplexType POCO for mapping the enum

 // Map

 
    [ComplexType]
    public class JobInstanceState
    {
        // FK + navigation property (must be virtual)
        [ForeignKey("JobInstanceStateLookup")]
        public int JobInstanceStateLookupId { getset; }
        public virtual JobInstanceStateLookup JobInstanceStateLookup { getset; }
        
        // ctors
        public JobInstanceState() : this(JobInstanceStateEnum.Ok) {}
        public JobInstanceState(JobInstanceStateEnum value)
        {
            JobInstanceStateLookupId = (int)value;
        }
        // implicit operators for auto casting the complex type to enum val
        public static implicit operator JobInstanceStateEnum(JobInstanceState type)
        {
            return (JobInstanceStateEnum)type.JobInstanceStateLookupId;
        }
        public static implicit operator JobInstanceState(JobInstanceStateEnum type)
        {
            return new JobInstanceState(type);
        } 
    }

 

 
Step 5 – DBContext and DBSets

 // DbContext – the Generator

 
    public class SpitfireContext : DbContext
    {   
        public DbSet<JobInstanceStateLookup> JobInstanceStateLookup { getset; }
        public DbSet<JobInstance> JobInstances { getset; }
        
    }
Step 6 – DB Initializer
// Initialize the DB – iterate over enum to populate lookup table
        public class Initializer : IDatabaseInitializer<MyContext>
        {
            public void InitializeDatabase(MyContext context)
            {
                if (!context.Database.Exists() || !context.Database.CompatibleWithModel(false))
                {
                    context.Database.Delete();
                    context.Database.Create();
                    var jobInstanceStateList = EnumExtensions.ConvertEnumToDictionary<JobInstanceStateEnum>().ToList();
                    jobInstanceStateList.ForEach(kvp => context.JobInstanceStateLookup.Add(
                        new JobInstanceStateLookup()
                            {
                                JobInstanceStateLookupId = kvp.Value,
                                Value = kvp.Key
                            }));
 
                    context.SaveChanges();
                }          
            }
        }
Step 7  - Unit Test
        [TestMethod]
        public void TestComplexTypeWithEnumToLookup()
        {
            // Arrange:
            DbDatabase.SetInitializer(new MyContext.Initializer());
            var db = new MyContext();
            var ji = new JobInstance()
                         { 
                           Blah   = "xxx",
                           Status = JobInstanceStateEnum.Aborted
                         };
            ji.Status = JobInstanceStateEnum.MissingResources; // The power of implicit operators
            // Act:
            db.JobInstances.Add(ji);
            db.SaveChanges();
 
// The type 'JobInstanceState' is mapped as a complex type. 
            // The Set method, DbSet objects, and DbEntityEntry objects can only be used with entity types, not complex types.
            // so theres no easy way to navigate to db.JobInstances.First().Status.JobInstanceStateLookup
            // which is good (albiet a leaky abstraction) because Code First doesnt support RO !
 
            var ji2 = db.JobInstances.First().Status;
            var enumString = JobInstanceStateEnum.MissingResources.ToString();
            var lookup = db.JobInstanceStateLookup.Where(l => l.Value == enumString).FirstOrDefault();
 
            // Assert:
            Assert.IsTrue(db.JobInstances.Count() > 0);
            
            Assert.AreEqual(ji2.JobInstanceStateLookupId, lookup.JobInstanceStateLookupId);
        }

 

 

Enjoy!

Posted on Wednesday, May 18, 2011 3:57 PM | Back to top


Comments on this post: Entity Framework 4.1 Code First – Mapping Enums to Lookup Tables

# re: Entity Framework 4.1 Code First – Mapping Enums to Lookup Tables
Requesting Gravatar...
Hiya

I can't get this to work. I keep getting the error


The type 'My.Name.Space.UnifiedQuoteStatus' has already been configured as a complex type. It cannot be reconfigured as an entity type.

Any idea what this might mean?
Left by Antony Koch on May 23, 2011 6:02 PM

# re: Entity Framework 4.1 Code First – Mapping Enums to Lookup Tables
Requesting Gravatar...
Actually, implementing your code as a spike throws the same error. I'm using EF 4.1.

Can you re-post it with it working? Are yuo using the older version of EF? I ask because

DatabaseGenerationOption is now defunct and

[DatabaseGenerated(DatabaseGeneratedOption.None)]

Is the correct syntax.
Left by Antony Koch on May 23, 2011 6:47 PM

# re: Entity Framework 4.1 Code First – Mapping Enums to Lookup Tables
Requesting Gravatar...
I'm using CTP 5 - It works on my machine! (cringe) - will check it with release version as soon as time permits.
cheers,
Josh
Left by Josh Reuben on May 24, 2011 7:12 PM

# re: Entity Framework 4.1 Code First – Mapping Enums to Lookup Tables
Requesting Gravatar...
the usual developer answer ;)

please let us know as I'm experiencing exactly the same problem using ef 4.1 referenced using nuget.

didn't know CTP 5 was available.

cheers
Left by Tom Miller on May 26, 2011 10:21 PM

# re: Entity Framework 4.1 Code First – Mapping Enums to Lookup Tables
Requesting Gravatar...
I get the same error.

According to http://msdn.microsoft.com/en-us/library/bb738472.aspx navigation properties on Complex Types are not allowed. This might have kicked in after CTP5 was released which would explain why it's not working with 4.1.
Left by Ben on Jun 06, 2011 9:54 AM

# re: Entity Framework 4.1 Code First – Mapping Enums to Lookup Tables
Requesting Gravatar...
If you just need enum, try this out: http://blogs.planetcloud.co.uk/mygreatdiscovery/post/Handling-enumerations-in-entity-framework.aspx

Left by Stefan Andersson on Nov 08, 2011 6:45 PM

Your comment:
 (will show your gravatar)


Copyright © JoshReuben | Powered by: GeeksWithBlogs.net | Join free