In EF6 we usually able to use this way to configure the Entity.
public class AccountMap : EntityTypeConfiguration
{
public AccountMap()
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?
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());
}
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 });
}
}