In EF6 we usually able to use this way to configure the Entity.
public class AccountMap : EntityTypeConfiguration<Account>
{
public AccountMap()
{
ToTable("Account");
HasKey(a => a.Id);
Property(a => a.Username).HasMaxLength(50);
Property(a => a.Email).HasMaxLength(255);
Property(a => a.Name).HasMaxLength(255);
}
}
How we can do in EF Core, since when the class I Inherit EntityTypeConfiguration that unable to find the class.
I download the EF Core raw source code from the GitHub, I can't find it. Can someone help on this?
Allows configuration to be performed for an entity type in a model. An EntityTypeConfiguration can be obtained via the Entity method on DbModelBuilder or a custom type derived from EntityTypeConfiguration can be registered via the Configurations property on DbModelBuilder.
The ModelBuilder is the class which is responsible for building the Model. The ModelBuilder builds the initial model from the entity classes that have DbSet Property in the context class, that we derive from the DbContext class. It then uses the conventions to create primary keys, Foreign keys, relationships etc.
OnModelCreating is not necessary, but at the same time will not hurt if called - that's why Sometimes it's there, sometimes not. Sometimes at the beginning of the method, other times at the end.
Since EF Core 2.0 there is IEntityTypeConfiguration<TEntity>
. You can use it like this:
class CustomerConfiguration : IEntityTypeConfiguration<Customer>
{
public void Configure(EntityTypeBuilder<Customer> builder)
{
builder.HasKey(c => c.AlternateKey);
builder.Property(c => c.Name).HasMaxLength(200);
}
}
...
// OnModelCreating
builder.ApplyConfiguration(new CustomerConfiguration());
More on this and other new features introduced in 2.0 can be found here.
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());
}
In EF7, you override OnModelCreating on the DbContext class you're implementing.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Account>()
.ForRelational(builder => builder.Table("Account"))
.Property(value => value.Username).MaxLength(50)
.Property(value => value.Email).MaxLength(255)
.Property(value => value.Name).MaxLength(255);
}
Since EF Core 2.2 you can add all configs (classes, which implemented IEntityTypeConfiguration interface) in one line in the method OnModelCreating in class, which is inherited from DbContext class
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//this will apply configs from separate classes which implemented IEntityTypeConfiguration<T>
modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
}
And, as it was mentioned in the previous answer, since EF Core 2.0, you can implement the interface IEntityTypeConfiguration, setup mapping configuration with using FluentAPI in Configure method.
public class QuestionAnswerConfig : IEntityTypeConfiguration<QuestionAnswer>
{
public void Configure(EntityTypeBuilder<QuestionAnswer> builder)
{
builder
.HasKey(bc => new { bc.QuestionId, bc.AnswerId });
builder
.HasOne(bc => bc.Question)
.WithMany(b => b.QuestionAnswers)
.HasForeignKey(bc => bc.QuestionId);
builder
.HasOne(bc => bc.Answer)
.WithMany(c => c.QuestionAnswers)
.HasForeignKey(bc => bc.AnswerId);
}
}
This is using current latest, beta 8. Try this:
public class AccountMap
{
public AccountMap(EntityTypeBuilder<Account> entityBuilder)
{
entityBuilder.HasKey(x => x.AccountId);
entityBuilder.Property(x => x.AccountId).IsRequired();
entityBuilder.Property(x => x.Username).IsRequired().HasMaxLength(50);
}
}
Then in your DbContext:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
new AccountMap(modelBuilder.Entity<Account>());
}
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 });
}
}
This is what I am doing in a project I'm currently working on.
public interface IEntityMappingConfiguration<T> where T : class
{
void Map(EntityTypeBuilder<T> builder);
}
public static class EntityMappingExtensions
{
public static ModelBuilder RegisterEntityMapping<TEntity, TMapping>(this ModelBuilder builder)
where TMapping : IEntityMappingConfiguration<TEntity>
where TEntity : class
{
var mapper = (IEntityMappingConfiguration<TEntity>)Activator.CreateInstance(typeof (TMapping));
mapper.Map(builder.Entity<TEntity>());
return builder;
}
}
Usage:
In your Context's OnModelCreating method:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder
.RegisterEntityMapping<Card, CardMapping>()
.RegisterEntityMapping<User, UserMapping>();
}
Example mapping class:
public class UserMapping : IEntityMappingConfiguration<User>
{
public void Map(EntityTypeBuilder<User> builder)
{
builder.ToTable("User");
builder.HasKey(m => m.Id);
builder.Property(m => m.Id).HasColumnName("UserId");
builder.Property(m => m.FirstName).IsRequired().HasMaxLength(64);
builder.Property(m => m.LastName).IsRequired().HasMaxLength(64);
builder.Property(m => m.DateOfBirth);
builder.Property(m => m.MobileNumber).IsRequired(false);
}
}
One other thing I like to do to take advantage of the folding behavior of Visual Studio 2015 is for an Entity called 'User', you name your mapping file 'User.Mapping.cs', Visual Studio will fold the file in the solution explorer so that it is contained under the entity class file.
I ended with this solution:
public interface IEntityMappingConfiguration
{
void Map(ModelBuilder b);
}
public interface IEntityMappingConfiguration<T> : IEntityMappingConfiguration where T : class
{
void Map(EntityTypeBuilder<T> builder);
}
public abstract class EntityMappingConfiguration<T> : IEntityMappingConfiguration<T> where T : class
{
public abstract void Map(EntityTypeBuilder<T> b);
public void Map(ModelBuilder b)
{
Map(b.Entity<T>());
}
}
public static class ModelBuilderExtenions
{
private static IEnumerable<Type> GetMappingTypes(this Assembly assembly, Type mappingInterface)
{
return assembly.GetTypes().Where(x => !x.IsAbstract && x.GetInterfaces().Any(y => y.GetTypeInfo().IsGenericType && y.GetGenericTypeDefinition() == mappingInterface));
}
public static void AddEntityConfigurationsFromAssembly(this ModelBuilder modelBuilder, Assembly assembly)
{
var mappingTypes = assembly.GetMappingTypes(typeof (IEntityMappingConfiguration<>));
foreach (var config in mappingTypes.Select(Activator.CreateInstance).Cast<IEntityMappingConfiguration>())
{
config.Map(modelBuilder);
}
}
}
Sample Use:
public abstract class PersonConfiguration : EntityMappingConfiguration<Person>
{
public override void Map(EntityTypeBuilder<Person> b)
{
b.ToTable("Person", "HumanResources")
.HasKey(p => p.PersonID);
b.Property(p => p.FirstName).HasMaxLength(50).IsRequired();
b.Property(p => p.MiddleName).HasMaxLength(50);
b.Property(p => p.LastName).HasMaxLength(50).IsRequired();
}
}
and
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.AddEntityConfigurationsFromAssembly(GetType().Assembly);
}
Just implement the IEntityTypeConfiguration
public abstract class EntityTypeConfiguration<TEntity> : IEntityTypeConfiguration<TEntity> where TEntity : class
{
public abstract void Configure(EntityTypeBuilder<TEntity> builder);
}
and then add it to your entity Context
public class ProductContext : DbContext, IDbContext
{
public ProductContext(DbContextOptions<ProductContext> options)
: base((DbContextOptions)options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfiguration(new ProductMap());
}
public DbSet<Entities.Product> Products { get; set; }
}
In ef core we have to impelement IEntityTypeConfiguration instead of EntityTypeConfiguration in this case we have full access to DbContext modelBuilder and we can use fluent api but in ef core this api is a litle bit diferent from previous versions. you can find more details on ef core model configuration on
https://www.learnentityframeworkcore.com/configuration/fluent-api
In Entity Framework Core 2.0:
I took Cocowalla's answer and adapted it for v2.0:
public static class ModelBuilderExtenions
{
private static IEnumerable<Type> GetMappingTypes(this Assembly assembly, Type mappingInterface)
{
return assembly.GetTypes().Where(x => !x.IsAbstract && x.GetInterfaces().Any(y => y.GetTypeInfo().IsGenericType && y.GetGenericTypeDefinition() == mappingInterface));
}
public static void AddEntityConfigurationsFromAssembly(this ModelBuilder modelBuilder, Assembly assembly)
{
// Types that do entity mapping
var mappingTypes = assembly.GetMappingTypes(typeof(IEntityTypeConfiguration<>));
// 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(modelBuilder, null);
// Create the mapping type and do the mapping
var mapper = Activator.CreateInstance(mappingType);
mapper.GetType().GetMethod("Configure").Invoke(mapper, new[] { entityBuilder });
}
}
}
And it's used in the DbContext like this:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.AddEntityConfigurationsFromAssembly(GetType().Assembly);
}
And this is how you create an entity type configuration for an entity:
public class UserUserRoleEntityTypeConfiguration : IEntityTypeConfiguration<UserUserRole>
{
public void Configure(EntityTypeBuilder<UserUserRole> builder)
{
builder.ToTable("UserUserRole");
// compound PK
builder.HasKey(p => new { p.UserId, p.UserRoleId });
}
}
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int RollNumber { get; set; }
public string Address { get; set; }
}
public class StudentMapper : IEntityTypeConfiguration<Student>
{
public void Configure(EntityTypeBuilder<Student> builder)
{
builder.ToTable("tbl_Students");
builder.HasKey(x => x.Id);
builder.Property(x => x.Address)
.HasMaxLength(250);
builder.Property(x => x.Name)
.HasMaxLength(50);
builder.Property(x => x.Name).HasColumnName("varchar_name");
}
}
public class DataContext : DbContext
{
public DataContext(DbContextOptions options): base(options)
{
}
public DbSet<Student> Students { get; set; }
//DbSets
protected override void OnModelCreating(ModelBuilder modelBuilder) {
//for fluent API approach and also we can create a separate mapper for each entity
#region student
modelBuilder.ApplyConfiguration(new StudentMapper());
#endregion
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With