Code First enumerations are placed in lookup tables

I have worked in many stores where they ran the first database model so lookup tables were always required. Your lookup table had to match your Enums in order for you to maintain the integrity of the database. I agree 100% with this idea, but found that when it comes to the first model of code, this is not available out of the box. I read somewhere that the EF team might add the ability to dynamically add Enums to your DB (via migration) in EF7, but they warned that this is not a promise.

So how do you (if at all) accomplish this? I'm going to provide my solution below in the answer and look forward to your feedback.

I am using EF 6.1.3 and .NET 4.5.1

+3


source to share


1 answer


So I'm not going to lie, my solution is a little in-depth, but I've been using it now for the past few days and I believe it works exactly the way I need it.

Start at the beginning, my base class I created:

public abstract class LookupTableBase
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int Id { get; set; }

    [Required]
    public string Name { get; set; }
}

      

Here is an example of one of my Entity Model lookup tables:

/// <summary>
///     Lookup Table for Enumeration AddressTypes
///     File Reference: DataAccessLayer/Enumerations/Locators.cs
///     DO NOT USE
///     SHOULD NOT BE AVAILABLE IN ENTITY MODELS
/// </summary>
[Table("AddressTypes", Schema = "Lookup")]
public class AddressType : LookupTableBase {}

      

Here is the listing that comes with this lookup table:

public enum AddressTypes
{
    [StringValue("")]
    Unknown = 0,

    [StringValue("Home")]
    Home = 1,

    [StringValue("Mailing")]
    Mailing = 2,

    [StringValue("Business")]
    Business = 3
}

      

The StringValue attribute is a custom attribute that I created (based on examples I found on the internet) that allow me to call:

AddressTypes.Home.GetStringValue();

      

That returns a string: Home

.

I add a Lookup Entity model to my DbSets so that the table is created, but I never refer directly to the Lookup Entity models in any of the other Entity models. Its sole purpose is to create database lookup tables so that I can create foreign key constraints for them.



public DbSet<AddressType> AddressTypes { get; set; }

      

In my OnModelCreating method for my context, I had to add this because the data annotation didn't go all the way:

modelBuilder.Entity<AddressType>()
            .Property(x => x.Id)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);

      

In my migration config file, I add this to the Seed method:

var addressTypeCount = Enum.GetValues(typeof (AddressTypes)).Length;
var addressTypes = new List<AddressType>();
for (var i = 1; i < addressTypeCount; i++) {
    addressTypes.Add(new AddressType {
                                         Id = i,
                                         Name = ((AddressTypes)i).GetStringValue()
                                     });
}
context.AddressTypes.AddOrUpdate(c => c.Id, addressTypes.ToArray());
context.SaveChanges();

      

Finally, in the migration file itself, I move all methods to create the lookup table to the top of the list, now I can add foreign key constraints to any table that references this enum. In my case, I took one more step. Since the migration class is partial, I created another partial class to match it. Two methods are created:

public void LookupDataUp()
public void LookupDataDown()

      

In the LookupDataUp method, I add all custom foreign keys and indexes to the LookupDataDown. I am deleting all my custom foreign keys and indexes.

When I run Update-Database, all my tables that used to have some kind of integer value that represented something (in this case AddressType) but had no real value now have a value that can be seen by associating it with it lookup table.

I admit it seems like a lot of work to get a small amount of data in the database, but now every time I delete / modify / add new items to my list, it automatically translates to the DB. Plus, as I said in the above question, this creates the integrity of the database by having the foreign key constraint in the "integer" field.

+5


source







All Articles