Last active
July 16, 2020 18:01
-
-
Save amkherad/dbf00c3e4eb45d30237c4cf790ce1178 to your computer and use it in GitHub Desktop.
EntityFrameworkConfigurationsApplier
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| public class DataContext : DbContext { | |
| private static readonly Lazy<Action<ModelBuilder>> EntityConfigurationApplier = | |
| new Lazy<Action<ModelBuilder>>( | |
| () => EntityConfigurationsApplier.CreateAutoApplierBuilder(typeof(DataContext)) | |
| ); | |
| protected override void OnModelCreating( | |
| ModelBuilder modelBuilder | |
| ) | |
| { | |
| base.OnModelCreating(modelBuilder); | |
| EntityConfigurationApplier.Value.Invoke(modelBuilder); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| using System.Linq.Expressions; | |
| using System.Reflection; | |
| using Microsoft.EntityFrameworkCore; | |
| namespace Infrastructure.Context | |
| { | |
| public class EntityConfigurationsApplier | |
| { | |
| public static Action<ModelBuilder> CreateAutoApplierBuilder( | |
| Type targetContextType | |
| ) | |
| { | |
| var configurations = targetContextType.Assembly | |
| .GetTypes() | |
| .Where(t => t.GetInterfaces() | |
| .Any(i => i.IsGenericType && | |
| i.GetGenericTypeDefinition() == | |
| typeof(IEntityTypeConfiguration<>))) | |
| .ToArray(); | |
| //uncomment these if you want to filter which EntityConfigurations should be applied on the target context | |
| //by creating a ApplyOnContextAttribute attribute class and decorate the EntityConfigurations with it to | |
| //specify which EntityConfiguration should be applied on which DbContext. | |
| //It's usefull in multi-context implementations. | |
| // configurations = configurations | |
| // .Where(t => | |
| // { | |
| // var attributes = t.GetCustomAttributes(); | |
| // var context = attributes.FirstOrDefault(a => a is ApplyOnContextAttribute); | |
| // if (context is ApplyOnContextAttribute applyOnContext) | |
| // { | |
| // return applyOnContext.TargetContext == targetContextType; | |
| // } | |
| // return false; | |
| // }) | |
| // .ToArray(); | |
| var applyConfigMethod = typeof(ModelBuilder) | |
| .GetMethods(BindingFlags.Public | BindingFlags.Instance) | |
| .FirstOrDefault(m => | |
| m.Name == nameof(ModelBuilder.ApplyConfiguration)); | |
| if (applyConfigMethod is null) | |
| { | |
| throw new InvalidOperationException(); | |
| } | |
| var modelBuilderParameter = Expression.Parameter(typeof(ModelBuilder), "modelBuilder"); | |
| var commands = new List<Expression>(); | |
| foreach (var config in configurations) | |
| { | |
| var entityType = config.GetInterfaces() | |
| .Single( | |
| i => i.IsGenericType && | |
| i.GetGenericTypeDefinition() == | |
| typeof(IEntityTypeConfiguration<>)) | |
| .GetGenericArguments() | |
| .Single(); | |
| var target = applyConfigMethod.MakeGenericMethod(entityType); | |
| var instance = Expression.New(config); | |
| var call = Expression.Call(modelBuilderParameter, target, instance); | |
| commands.Add(call); | |
| } | |
| var body = Expression.Block(commands); | |
| var lambda = Expression.Lambda<Action<ModelBuilder>>(body, modelBuilderParameter); | |
| return lambda.Compile(); | |
| } | |
| } | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Here's a piece of code to apply multiple
IEntityTypeConfigurationwithout explicitly calling them.This method creates a delegate that you can call to configure all entities in a specific ModelBuilder.
This method does nothing for caching, you can cache the generated delegate like this: