Jasinski Technical Wiki

Navigation

Home Page
Index
All Pages

Quick Search
»
Advanced Search »

Contributor Links

Create a new Page
Administration
File Management
Login/Logout
Your Profile

Other Wiki Sections

Software

PoweredBy

Extension Method to Seed Enum Values into Database Table - Entity Framework Code First

RSS
Modified on Thu, Jun 18, 2020, 2:09 PM by Administrator Categorized as Entity Framework Code First

Overview

When an enum is persisted in a database table, it is better if the Code First entity doesn't use a (SQL Server) IDENTITY field. This is recommended for two reasons.

  • Having an IDENTITY field on an enum table requires the use of IDENTITY_INSERT, which Entity Framework doesn't play with well.
  • Changing from an IDENTITY field to a non-IDENTITY field is a troublesome endeavor in SQL Server. It requires the creation of a temporary table, the copying of data between tables, and a few table renames.

For these reasons, it is useful to have a base class to support the creation and seeding of enum tables in Entity Framework.

References

The AddSpaces extension method can be found here.

Reusable Code - EF6

Add this code within your DAL project/namespace.

public abstract class EnumDbEntity<TEnum>
        where TEnum : struct, IConvertible
{
    [Required]
    public TEnum Id { get; set; }

    [Required, StringLength(100)]
    public string DisplayName { get; set; }

    /// <summary>
    /// TODO: Override this method where needed, especially if the derived class has extra fields.
    /// </summary>
    /// <param name="value"></param>
    /// <param name="addSpaces"></param>
    /// <returns></returns>
    public virtual EnumDbEntity<TEnum> InitForSeeding(TEnum value, bool addSpaces = true)
    {
        Id = value;
        DisplayName = EnumHelper<TEnum>.GetDisplayValue(value, addSpaces);
        return this;
    }

}

public static class EnumDbEntityExtensions
{
    public static void SeedEnumTable<TEnum, TEntity>(this IDbSet<TEntity> dbSet, bool addSpaces = true)
        where TEnum : struct, IConvertible
        where TEntity : EnumDbEntity<TEnum>, new()
    {
        if (!typeof(TEnum).IsEnum) throw new ArgumentException("TEnum must be an enumerated type");

        var itemValues = (TEnum[])Enum.GetValues(typeof(TEnum));

        foreach (var itemValue in itemValues)
        {
            var item = new TEntity();
            item.InitForSeeding(itemValue, addSpaces);
            dbSet.AddOrUpdate(a => a.Id, item);
        }
    }
}


/* Reference
    * https://stackoverflow.com/questions/13099834/how-to-get-the-display-name-attribute-of-an-enum-member-via-mvc-razor-code */
public static class EnumHelper<T>
    where T : struct, IConvertible
{

    public static string GetDisplayValue(T value, bool addSpaces = true)
    {
        var ret = String.Empty;
        var fieldInfo = value.GetType().GetField(value.ToString());

        if (fieldInfo == null)
        {
            return "Display Name Unknown";
        }

        var dispAttrib = fieldInfo.GetCustomAttributes(typeof(DisplayAttribute), false) as DisplayAttribute[];

        if (dispAttrib != null)
        {
            if (dispAttrib.Length > 0)
            {
                ret = dispAttrib[0].Name;
            }
            else
            {
                ret = value.ToString();

                if (addSpaces)
                {
                    ret = ret.AddSpaces();
                }
            }
        }
        return ret;
    }
}

Implementation Sample Code - EF6

Enum and Database Entity

public enum OrderStatusEnum
{
    Active,
    Inactive
}

public class OrderStatus : EnumDbEntity<OrderStatusEnum>
{ }

Seeding the Table - EF6

context.OrderStatuses.SeedEnumTable<OrderStatusEnum, OrderStatus>();

Reusable Code - EF Core

using Microsoft.EntityFrameworkCore;
using NetSoft.iPathPro.Common;
using System;
using System.ComponentModel.DataAnnotations;

public abstract class EnumDbEntity<TEnum>
        where TEnum : struct, IConvertible
{
    [Required]
    public TEnum Id { get; set; }

    [Required, StringLength(100)]
    public string DisplayName { get; set; }

    /// <summary>
    /// TODO: Override this method where needed, especially if the derived class has extra fields.
    /// </summary>
    /// <param name="value"></param>
    /// <param name="addSpaces"></param>
    /// <returns></returns>
    public virtual EnumDbEntity<TEnum> InitForSeeding(TEnum value, bool addSpaces = true)
    {
        Id = value;
        DisplayName = EnumHelper<TEnum>.GetDisplayValue(value, addSpaces);
        return this;
    }

}

public static class EnumDbEntityExtensions
{
    /*--- EF Core Version ---*/
    /* Usage: within DbContext's "protected override void OnModelCreating(ModelBuilder mb)" add the */
    /* following code: mb.SeedEnumTable<TEnum, TEntity>(); */
    /* Be sure to subsitute your enum and entity class for TEnum and TEntity, respectively. */
    public static void SeedEnumTable<TEnum, TEntity>(this ModelBuilder mb, bool addSpaces = true)
        where TEnum : struct, IConvertible
        where TEntity : EnumDbEntity<TEnum>, new()
    {
        if (!typeof(TEnum).IsEnum) throw new ArgumentException("TEnum must be an enumerated type");

        var itemValues = (TEnum[])Enum.GetValues(typeof(TEnum));

        foreach (var itemValue in itemValues)
        {
            var item = new TEntity();
            item.InitForSeeding(itemValue, addSpaces);
            mb.Entity<TEntity>().HasData(item);
        }
    }


}


/* Reference
    * https://stackoverflow.com/questions/13099834/how-to-get-the-display-name-attribute-of-an-enum-member-via-mvc-razor-code */
public static class EnumHelper<T>
    where T : struct, IConvertible
{

    public static string GetDisplayValue(T value, bool addSpaces = true)
    {
        var ret = String.Empty;
        var fieldInfo = value.GetType().GetField(value.ToString());

        if (fieldInfo == null)
        {
            return "Display Name Unknown";
        }

        var dispAttrib = fieldInfo.GetCustomAttributes(typeof(DisplayAttribute), false) as DisplayAttribute[];

        if (dispAttrib != null)
        {
            if (dispAttrib.Length > 0)
            {
                ret = dispAttrib[0].Name;
            }
            else
            {
                ret = value.ToString();

                if (addSpaces)
                {
                    ret = ret.AddSpaces();
                }
            }
        }
        return ret;
    }
}

Implementation Sample Code - EF Core

Enum and Database Entity

public enum OrderStatusEnum
{
    Active,
    Inactive
}

public class OrderStatus : EnumDbEntity<OrderStatusEnum>
{ }

Seeding the Table - EF Core

protected override void OnModelCreating(ModelBuilder mb)
{
    mb.SeedEnumTable<OrderStatusEnum, OrderStatus>();
}

ScrewTurn Wiki version 3.0.1.400. Some of the icons created by FamFamFam. Except where noted, all contents Copyright © 1999-2020, Patrick Jasinski.