EF Core Mapping EntityTypeConfiguration

Dans EF6, nous pouvons généralement utiliser cette méthode pour configurer l’entité.

public class AccountMap : EntityTypeConfiguration { 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); } } 

Comment pouvons-nous faire dans EF Core, depuis quand la classe I Hérite EntityTypeConfiguration qui ne peut pas trouver la classe.

Je télécharge le code source brut EF Core depuis GitHub, je ne le trouve pas. Quelqu’un peut-il aider à ce sujet?

Depuis EF Core 2.0, il y a IEntityTypeConfiguration . Vous pouvez l’utiliser comme ceci:

 class CustomerConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.HasKey(c => c.AlternateKey); builder.Property(c => c.Name).HasMaxLength(200); } } ... // OnModelCreating builder.ApplyConfiguration(new CustomerConfiguration()); 

Vous trouverez plus d’informations à ce sujet et d’autres nouvelles fonctionnalités introduites dans la version 2.0 ici .

Vous pouvez y parvenir grâce à des types supplémentaires simples:

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

Usage:

 internal class UserConfiguration : DbEntityConfiguration { public override void Configure(EntityTypeBuilder 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()); } 

Dans EF7, vous remplacez OnModelCreating sur la classe DbContext que vous implémentez.

 protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity() .ForRelational(builder => builder.Table("Account")) .Property(value => value.Username).MaxLength(50) .Property(value => value.Email).MaxLength(255) .Property(value => value.Name).MaxLength(255); } 

Ceci utilise la dernière version bêta 8. Essayez ceci:

 public class AccountMap { public AccountMap(EntityTypeBuilder entityBuilder) { entityBuilder.HasKey(x => x.AccountId); entityBuilder.Property(x => x.AccountId).IsRequired(); entityBuilder.Property(x => x.Username).IsRequired().HasMaxLength(50); } } 

Puis dans votre DbContext:

  protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); new AccountMap(modelBuilder.Entity()); } 

Vous pouvez utiliser la reflection pour faire les choses de manière très similaire à leur fonctionnement dans EF6, avec une classe de mappage distincte pour chaque entité. Cela fonctionne en RC1 final:

Tout d’abord, créez une interface pour vos types de mappage:

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

Créez ensuite une classe de mappage pour chacune de vos entités, par exemple pour une classe Person :

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

Maintenant, la magie de reflection dans OnModelCreating dans votre implémentation DbContext :

 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 var genericEntityMethod = entityMethod.MakeGenericMethod(genericTypeArg); // Invoke builder.Entity 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 }); } } 

C’est ce que je fais dans un projet sur lequel je travaille actuellement.

 public interface IEntityMappingConfiguration where T : class { void Map(EntityTypeBuilder builder); } public static class EntityMappingExtensions { public static ModelBuilder RegisterEntityMapping(this ModelBuilder builder) where TMapping : IEntityMappingConfiguration where TEntity : class { var mapper = (IEntityMappingConfiguration)Activator.CreateInstance(typeof (TMapping)); mapper.Map(builder.Entity()); return builder; } } 

Usage:

Dans la méthode OnModelCreating de votre contexte:

  protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); builder .RegisterEntityMapping() .RegisterEntityMapping(); } 

Exemple de classe de mappage:

 public class UserMapping : IEntityMappingConfiguration { public void Map(EntityTypeBuilder 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); } } 

Une autre chose que j’aime faire pour tirer parti du comportement de Visual Studio 2015 en matière de pliage concerne une entité appelée «Utilisateur», vous nommez votre fichier de mappage «User.Mapping.cs», Visual Studio pliera le fichier dans l’explorateur de solutions. pour qu’il soit contenu dans le fichier de classe d’entité.

J’ai fini avec cette solution:

 public interface IEntityMappingConfiguration { void Map(ModelBuilder b); } public interface IEntityMappingConfiguration : IEntityMappingConfiguration where T : class { void Map(EntityTypeBuilder builder); } public abstract class EntityMappingConfiguration : IEntityMappingConfiguration where T : class { public abstract void Map(EntityTypeBuilder b); public void Map(ModelBuilder b) { Map(b.Entity()); } } public static class ModelBuilderExtenions { private static IEnumerable 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()) { config.Map(modelBuilder); } } } 

Exemple d’utilisation:

 public abstract class PersonConfiguration : EntityMappingConfiguration { public override void Map(EntityTypeBuilder 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(); } } 

et

 protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.AddEntityConfigurationsFromAssembly(GetType().Assembly); } 

Eh bien, voici le problème de l’amélioration du repository EF7 Github: https://github.com/aspnet/EntityFramework/issues/2805

Vous pouvez suivre le problème directement là-bas, même si celui-ci est toujours en attente de traitement sans priorité désignée.

Il suffit d’implémenter IEntityTypeConfiguration

 public abstract class EntityTypeConfiguration : IEntityTypeConfiguration where TEntity : class { public abstract void Configure(EntityTypeBuilder builder); } 

puis ajoutez-le à votre entité Contexte

 public class ProductContext : DbContext, IDbContext { public ProductContext(DbContextOptions options) : base((DbContextOptions)options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.ApplyConfiguration(new ProductMap()); } public DbSet Products { get; set; } } 

Ai-je raison?

 public class SmartModelBuilder where T : class { private ModelBuilder _builder { get; set; } private Action> _entityAction { get; set; } public SmartModelBuilder(ModelBuilder builder, Action> entityAction) { this._builder = builder; this._entityAction = entityAction; this._builder.Entity(_entityAction); } } 

Je peux passer la config:

  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); new SmartModelBuilder(builder, entity => entity.Property(b => b.Url).Required()); } 

J’ai suivi une approche similaire à la façon dont Microsoft a implémenté ForSqlServerToTable

en utilisant la méthode d’extension …

l’indicateur partiel est requirejs si vous souhaitez utiliser le même nom de classe dans plusieurs fichiers

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

Ensuite, dans le DataContext OnModelCreating, faites votre appel pour chaque extension …

  public class DataContext : IdentityDbContext { 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().AddFluentMapping(); builder.Entity().AddFluentMapping(); } 

De cette façon, nous suivons le même schéma utilisé par les autres méthodes de création.

Qu’est-ce que tu aimes?

Dans ef core, nous devons améliorer IEntityTypeConfiguration au lieu de EntityTypeConfiguration dans ce cas, nous avons un access complet à DbContext modelBuilder et nous pouvons utiliser des api courants, mais dans ef core, cette api est légèrement différente des versions précédentes. vous pouvez trouver plus de détails sur la configuration du modèle de base ef sur

https://www.learnentityframeworkcore.com/configuration/fluent-api

Dans Entity Framework Core 2.0:

J’ai pris la réponse de Cocowalla et je l’ai adaptée pour la v2.0:

  public static class ModelBuilderExtenions { private static IEnumerable 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 var genericEntityMethod = entityMethod.MakeGenericMethod(genericTypeArg); // Invoke builder.Entity 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 }); } } } 

Et il est utilisé dans DbContext comme ceci:

  protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.AddEntityConfigurationsFromAssembly(GetType().Assembly); } 

Et c’est ainsi que vous créez une configuration de type d’entité pour une entité:

  public class UserUserRoleEntityTypeConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.ToTable("UserUserRole"); // compound PK builder.HasKey(p => new { p.UserId, p.UserRoleId }); } } 

J’ai un projet qui vous permet de configurer des entités en dehors de DbContext.OnModelCreating Vous configurez chaque entité dans une classe séparée qui hérite de StaticDotNet.EntityFrameworkCore.ModelConfiguration.EntityTypeConfiguration

Vous devez d’abord créer une classe qui hérite de StaticDotNet.EntityFrameworkCore.ModelConfiguration.EntityTypeConfigurationTEntity est la classe que vous souhaitez configurer.

 using StaticDotNet.EntityFrameworkCore.ModelConfiguration; using Microsoft.EntityFrameworkCore.Metadata.Builders; public class ExampleEntityConfiguration : EntityTypeConfiguration { public override void Configure( EntityTypeBuilder builder ) { //Add configuration just like you do in DbContext.OnModelCreating } } 

Ensuite, dans votre classe de démarrage, vous devez simplement indiquer à Entity Framework où trouver toutes vos classes de configuration lorsque vous configurez votre DbContext.

 using StaticDotNet.EntityFrameworkCore.ModelConfiguration; public void ConfigureServices(IServiceCollection services) { Assembly[] assemblies = new Assembly[] { // Add your assembiles here. }; services.AddDbContext( x => x .AddEntityTypeConfigurations( assemblies ) ); } 

Il existe également une option pour append des configurations de type à l’aide d’un fournisseur. Le repository a une documentation complète sur la façon de l’utiliser.

https://github.com/john-t-white/StaticDotNet.EntityFrameworkCore.ModelConfiguration