EF Core Mapping EntityTypeConfiguration

后端 未结 15 1232
花落未央
花落未央 2020-11-30 18:26

In EF6 we usually able to use this way to configure the Entity.

public class AccountMap : EntityTypeConfiguration
{
    public AccountMap()
           


        
相关标签:
15条回答
  • 2020-11-30 19:16

    I followed a similar approach to the way Microsoft implemented ForSqlServerToTable

    using extension method...

    the partial flag is required if you want to use the same class name in multiple files

    public class ConsignorUser
    {
        public int ConsignorId { get; set; }
    
        public string UserId { get; set; }
    
        public virtual Consignor Consignor { get; set; }
        public virtual User User { get; set; }
    
    }
    
    public static partial class Entity_FluentMappings
    {
        public static EntityTypeBuilder<ConsignorUser> AddFluentMapping<TEntity> (
            this EntityTypeBuilder<ConsignorUser> entityTypeBuilder) 
            where TEntity : ConsignorUser
        {
           entityTypeBuilder.HasKey(x => new { x.ConsignorId, x.UserId });
           return entityTypeBuilder;
        }      
    }
    

    Then in the DataContext OnModelCreating make your call for each extension...

     public class DataContext : IdentityDbContext<User>
    {
    
        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);
            // Customize the ASP.NET Identity model and override the defaults if needed.
            // For example, you can rename the ASP.NET Identity table names and more.
            // Add your customizations after calling base.OnModelCreating(builder);
    
            builder.Entity<ConsignorUser>().AddFluentMapping<ConsignorUser>();
            builder.Entity<DealerUser>().AddFluentMapping<DealerUser>();           
    
        }
    

    This way we are following the same pattern used by the other builder methods.

    What do you thing?

    0 讨论(0)
  • 2020-11-30 19:17

    You can achieve this through some simple additional types:

    internal static class ModelBuilderExtensions
    {
       public static void AddConfiguration<TEntity>(
         this ModelBuilder modelBuilder, 
         DbEntityConfiguration<TEntity> entityConfiguration) where TEntity : class
       {     
           modelBuilder.Entity<TEntity>(entityConfiguration.Configure);
       }
    }
    
    internal abstract class DbEntityConfiguration<TEntity> where TEntity : class
    {     
        public abstract void Configure(EntityTypeBuilder<TEntity> entity);
    }
    

    Usage:

    internal class UserConfiguration : DbEntityConfiguration<UserDto>
    {
        public override void Configure(EntityTypeBuilder<UserDto> entity)
        {
            entity.ToTable("User");
            entity.HasKey(c => c.Id);
            entity.Property(c => c.Username).HasMaxLength(255).IsRequired();
            // etc.
        }
    }
    
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
    
        modelBuilder.AddConfiguration(new UserConfiguration());
    }
    
    0 讨论(0)
  • 2020-11-30 19:17

    You can use reflection to do things very similarly to how they work in EF6, with a separate mapping class for each entity. This works in RC1 final:

    First, create an interface for your mapping types:

    public interface IEntityTypeConfiguration<TEntityType> where TEntityType : class
    {
        void Map(EntityTypeBuilder<TEntityType> builder);
    }
    

    Then create a mapping class for each of your entities, e.g. for a Person class:

    public class PersonMap : IEntityTypeConfiguration<Person>
    {
        public void Map(EntityTypeBuilder<Person> builder)
        {
            builder.HasKey(x => x.Id);
            builder.Property(x => x.Name).IsRequired().HasMaxLength(100);
        }
    }
    

    Now, the reflection magic in OnModelCreating in your DbContext implementation:

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
    
        // Interface that all of our Entity maps implement
        var mappingInterface = typeof(IEntityTypeConfiguration<>);
    
        // Types that do entity mapping
        var mappingTypes = typeof(DataContext).GetTypeInfo().Assembly.GetTypes()
            .Where(x => x.GetInterfaces().Any(y => y.GetTypeInfo().IsGenericType && y.GetGenericTypeDefinition() == mappingInterface));
    
        // Get the generic Entity method of the ModelBuilder type
        var entityMethod = typeof(ModelBuilder).GetMethods()
            .Single(x => x.Name == "Entity" && 
                    x.IsGenericMethod && 
                    x.ReturnType.Name == "EntityTypeBuilder`1");
    
        foreach (var mappingType in mappingTypes)
        {
            // Get the type of entity to be mapped
            var genericTypeArg = mappingType.GetInterfaces().Single().GenericTypeArguments.Single();
    
            // Get the method builder.Entity<TEntity>
            var genericEntityMethod = entityMethod.MakeGenericMethod(genericTypeArg);
    
            // Invoke builder.Entity<TEntity> to get a builder for the entity to be mapped
            var entityBuilder = genericEntityMethod.Invoke(builder, null);
    
            // Create the mapping type and do the mapping
            var mapper = Activator.CreateInstance(mappingType);
            mapper.GetType().GetMethod("Map").Invoke(mapper, new[] { entityBuilder });
        }
    }
    
    0 讨论(0)
提交回复
热议问题