private static bool ShouldSkip(Type propertyType, EnumLookupOptions enumOptions) { if (!propertyType.IsEnumOrNullableEnumType()) { return(true); } if (enumOptions.UseEnumsWithAttributesOnly && !propertyType.HasEnumLookupAttribute()) { return(true); } return(false); }
private static Type GetEnumLookupEntityType(EnumLookupOptions enumOptions, bool usesDescription, Type enumType) { Type concreteType; if (usesDescription) { concreteType = enumOptions.UseNumberLookup ? typeof(EnumWithNumberLookupAndDescription <>).MakeGenericType(enumType) : typeof(EnumWithStringLookupAndDescription <>).MakeGenericType(enumType); } else { concreteType = enumOptions.UseNumberLookup ? typeof(EnumWithNumberLookup <>).MakeGenericType(enumType) : typeof(EnumWithStringLookup <>).MakeGenericType(enumType); } return(concreteType); }
public static void ConfigureEnumLookup(this ModelBuilder modelBuilder, EnumLookupOptions enumOptions) { foreach (IMutableProperty property in modelBuilder.Model.GetEntityTypes().SelectMany(x => x.GetProperties()).ToList()) { IMutableEntityType entityType = property.DeclaringEntityType; if (entityType.IsOwned()) { continue; } ConfigureEnumLookupForProperty(modelBuilder, enumOptions, property, (enumLookupEntityType) => { modelBuilder.Entity(entityType.Name) .HasOne(enumLookupEntityType) .WithMany() .HasPrincipalKey("Id") .HasForeignKey(property.Name) .OnDelete(enumOptions.DeleteBehavior); }, (valueConverter) => { modelBuilder.Entity(entityType.Name).Property(property.Name).HasConversion(valueConverter); }); } }
// See https://github.com/aspnet/EntityFrameworkCore/issues/12248#issuecomment-395450990 public static void ConfigureEnumLookup(this ModelBuilder modelBuilder, EnumLookupOptions enumOptions) { foreach (IMutableProperty property in modelBuilder.Model.GetEntityTypes().SelectMany(x => x.GetProperties()).ToList()) { Type propertyType = property.ClrType; if (!propertyType.IsEnumOrNullableEnumType()) { continue; } if (enumOptions.UseEnumsWithAttributesOnly && !propertyType.HasEnumLookupAttribute()) { continue; } IMutableEntityType entityType = property.DeclaringEntityType; Dictionary <int, string> enumValueDescriptions = Enum.GetValues(propertyType.GetEnumOrNullableEnumType()) .Cast <Enum>() .ToDictionary(Convert.ToInt32, GetEnumDescription); bool usesDescription = enumValueDescriptions.Values.Any(x => x != null); Type concreteType; if (usesDescription) { concreteType = enumOptions.UseNumberLookup ? typeof(EnumWithNumberLookupAndDescription <>).MakeGenericType(propertyType.GetEnumOrNullableEnumType()) : typeof(EnumWithStringLookupAndDescription <>).MakeGenericType(propertyType.GetEnumOrNullableEnumType()); } else { concreteType = enumOptions.UseNumberLookup ? typeof(EnumWithNumberLookup <>).MakeGenericType(propertyType.GetEnumOrNullableEnumType()) : typeof(EnumWithStringLookup <>).MakeGenericType(propertyType.GetEnumOrNullableEnumType()); } EntityTypeBuilder enumLookupBuilder = modelBuilder.Entity(concreteType); string typeName = propertyType.GetEnumOrNullableEnumType().Name; string tableName = enumOptions.NamingFunction(typeName); enumLookupBuilder.ToTable(tableName); string keyName = enumOptions.UseNumberLookup ? nameof(EnumWithNumberLookup <Enum> .Id) : nameof(EnumWithStringLookup <Enum> .Id); modelBuilder.Entity(entityType.Name).HasOne(concreteType).WithMany().HasPrincipalKey(keyName).HasForeignKey(property.Name); if (enumOptions.UseNumberLookup) { modelBuilder.Entity(concreteType).HasIndex(nameof(EnumWithNumberLookup <Enum> .Name)).IsUnique(); } else { Type converterType = typeof(EnumToStringConverter <>).MakeGenericType(propertyType.GetEnumOrNullableEnumType()); ValueConverter valueConverter = (ValueConverter)Activator.CreateInstance(converterType, new object[] { null }); modelBuilder.Entity(entityType.Name).Property(property.Name).HasConversion(valueConverter); modelBuilder.Entity(concreteType).Property(keyName).HasConversion(valueConverter); } if (ConcreteTypeSeededList.Contains(concreteType)) { continue; } ConcreteTypeSeededList.Add(concreteType); // TODO: Check status of https://github.com/aspnet/EntityFrameworkCore/issues/12194 before using migrations object[] data = Enum.GetValues(propertyType.GetEnumOrNullableEnumType()) .OfType <object>() .Select(x => { object instance = Activator.CreateInstance(concreteType); if (enumOptions.UseNumberLookup) { concreteType.GetProperty(nameof(EnumWithNumberLookup <object> .Id)).SetValue(instance, x); concreteType.GetProperty(nameof(EnumWithNumberLookup <object> .Name)).SetValue(instance, x.ToString()); if (usesDescription) { concreteType.GetProperty(nameof(EnumWithNumberLookupAndDescription <object> .Description)) .SetValue(instance, enumValueDescriptions[(int)x]); } } else { concreteType.GetProperty(nameof(EnumWithStringLookup <object> .Id)).SetValue(instance, x); if (usesDescription) { concreteType.GetProperty(nameof(EnumWithNumberLookupAndDescription <object> .Description)) .SetValue(instance, enumValueDescriptions[(int)x]); } } return(instance); }) .ToArray(); enumLookupBuilder.HasData(data); } }
// See https://github.com/aspnet/EntityFrameworkCore/issues/12248#issuecomment-395450990 private static void ConfigureEnumLookupForProperty(ModelBuilder modelBuilder, EnumLookupOptions enumOptions, IMutableProperty property, Action <Type> configureEntityType, Action <ValueConverter> configureEntityTypeConversion) { Type propertyType = property.ClrType; if (ShouldSkip(propertyType, enumOptions)) { return; } Type enumType = propertyType.GetEnumOrNullableEnumType(); Dictionary <int, string> enumValueDescriptions = GetEnumValueDescriptions(enumType); bool usesDescription = enumValueDescriptions.Values.Any(x => x != null); Type enumLookupEntityType = GetEnumLookupEntityType(enumOptions, usesDescription, enumType); bool shouldSkipEnumLookupTableConfiguration = modelBuilder.Model.FindEntityType(enumLookupEntityType) != null; configureEntityType(enumLookupEntityType); ValueConverter valueConverter = GetValueConverter(enumType); if (!enumOptions.UseNumberLookup) { configureEntityTypeConversion(valueConverter); } if (shouldSkipEnumLookupTableConfiguration) { return; } EntityTypeBuilder enumLookupBuilder = modelBuilder.Entity(enumLookupEntityType); ConfigureEnumLookupTable(enumLookupBuilder, enumOptions, enumType); if (enumOptions.UseNumberLookup) { modelBuilder.Entity(enumLookupEntityType).HasIndex("Name").IsUnique(); } else { modelBuilder.Entity(enumLookupEntityType).Property("Id").HasConversion(valueConverter); } // TODO: Check status of https://github.com/aspnet/EntityFrameworkCore/issues/12194 before using migrations enumLookupBuilder.HasData(GetEnumData(enumType, enumLookupEntityType, enumOptions.UseNumberLookup, usesDescription, enumValueDescriptions)); }
public static void ConfigureOwnedEnumLookup <TEntity, TDependentEntity>( this OwnedNavigationBuilder <TEntity, TDependentEntity> ownedNavigationBuilder, EnumLookupOptions enumOptions, ModelBuilder modelBuilder) where TEntity : class where TDependentEntity : class { foreach (IMutableProperty property in ownedNavigationBuilder.OwnedEntityType.GetProperties().ToList()) { ConfigureEnumLookupForProperty(modelBuilder, enumOptions, property, (enumLookupEntityType) => { ownedNavigationBuilder.HasOne(enumLookupEntityType) .WithMany() .HasPrincipalKey("Id") .HasForeignKey(property.Name) .OnDelete(enumOptions.DeleteBehavior); }, (valueConverter) => { ownedNavigationBuilder.Property(property.Name).HasConversion(valueConverter); }); } }
private static void ConfigureEnumLookupTable(EntityTypeBuilder enumLookupBuilder, EnumLookupOptions enumOptions, Type enumType) { string typeName = enumType.Name; string tableName = enumOptions.NamingFunction(typeName); enumLookupBuilder.ToTable(tableName); }