EF核心映射EntityTypeConfiguration
在EF6中我们通常可以用这种方式来configuration实体
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); } }
我们如何在EF Core中做到这一点,因为当我inheritanceEntityTypeConfiguration类时,无法find类。
我从github上下载了EF Core原始代码,我找不到它。 有人可以帮助这一点。
你可以通过一些简单的附加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); }
用法:
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()); }
在EF7中,您可以重写正在实现的DbContext类的OnModelCreating。
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); }
这是使用最新的,testing版8.试试这个:
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); } }
然后在你的DbContext中:
protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); new AccountMap(modelBuilder.Entity<Account>()); }
在EF Core 2.0中,有IEntityTypeConfiguration<TEntity>
。 你可以像这样使用它:
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());
更多关于这个和2.0中的其他新function可以在这里find。
您可以使用reflection来完成与EF6中的工作非常相似的操作,并为每个实体分别设置一个映射类。 这在RC1的最后作品:
首先,为您的映射types创build一个接口:
public interface IEntityTypeConfiguration<TEntityType> where TEntityType : class { void Map(EntityTypeBuilder<TEntityType> builder); }
然后为每个实体创build一个映射类,例如Person
类:
public class PersonMap : IEntityTypeConfiguration<Person> { public void Map(EntityTypeBuilder<Person> builder) { builder.HasKey(x => x.Id); builder.Property(x => x.Name).IsRequired().HasMaxLength(100); } }
现在,在DbContext
实现中的OnModelCreating
中reflection魔术:
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 }); } }
这正是我正在从事的一个项目。
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; } }
用法:
在你的Context的OnModelCreating方法中:
protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); builder .RegisterEntityMapping<Card, CardMapping>() .RegisterEntityMapping<User, UserMapping>(); }
示例映射类:
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); } }
另一件事我喜欢做的利用Visual Studio 2015的折叠行为是为实体称为“用户”,您的映射文件名为User.Mapping.cs,Visual Studio将在解决scheme资源pipe理器中折叠文件所以它包含在实体类文件中。
我以这个解决scheme结束了:
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); } } }
示例使用:
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(); } }
和
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.AddEntityConfigurationsFromAssembly(GetType().Assembly); }
那么这里是EF7 Github回购增强的问题: https : //github.com/aspnet/EntityFramework/issues/2805
您可以直接在那里跟踪问题,尽pipe它仍然只在没有指定优先级的积压。
我对吗?
public class SmartModelBuilder<T> where T : class { private ModelBuilder _builder { get; set; } private Action<EntityTypeBuilder<T>> _entityAction { get; set; } public SmartModelBuilder(ModelBuilder builder, Action<EntityTypeBuilder<T>> entityAction) { this._builder = builder; this._entityAction = entityAction; this._builder.Entity<T>(_entityAction); } }
我可以通过configuration:
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<Blog>(builder, entity => entity.Property(b => b.Url).Required()); }
我遵循了微软实现ForSqlServerToTable的方法
使用扩展方法…
如果要在多个文件中使用相同的类名,则需要部分标志
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; } }
然后在DataContext的OnModelCreating使每个扩展的呼叫…
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>(); }
这样我们就可以遵循其他构build器方法所使用的相同模式。
你什么事?
我有一个项目,允许您configuration实体之外的DbContext.OnModelCreating
您configuration每个实体在一个单独的类从StaticDotNet.EntityFrameworkCore.ModelConfiguration.EntityTypeConfiguration
首先,您需要创build一个inheritance自StaticDotNet.EntityFrameworkCore.ModelConfiguration.EntityTypeConfiguration<TEntity>
的类,其中TEntity
是要configuration的类。
using StaticDotNet.EntityFrameworkCore.ModelConfiguration; using Microsoft.EntityFrameworkCore.Metadata.Builders; public class ExampleEntityConfiguration : EntityTypeConfiguration<ExampleEntity> { public override void Configure( EntityTypeBuilder<ExampleEntity> builder ) { //Add configuration just like you do in DbContext.OnModelCreating } }
然后,在您的Startup类中,只需要在configurationDbContext时告诉Entity Framework在哪里可以find所有的configuration类。
using StaticDotNet.EntityFrameworkCore.ModelConfiguration; public void ConfigureServices(IServiceCollection services) { Assembly[] assemblies = new Assembly[] { // Add your assembiles here. }; services.AddDbContext<ExampleDbContext>( x => x .AddEntityTypeConfigurations( assemblies ) ); }
还有一个使用提供者添加typesconfiguration的选项。 回购有完整的文件如何使用它。
https://github.com/john-t-white/StaticDotNet.EntityFrameworkCore.ModelConfiguration
- int vs const int&
- 如何使用Fiddlerdebugging任何应用程序的stream量(例如,C#/ WPF应用程序)
- 为什么使用C#类System.Random而不是System.Security.Cryptography.RandomNumberGenerator?
- 将列表框绑定到列表<object>
- 检测远程桌面连接
- Visual Studio:多个后期构build命令?
- 将调用std :: vector :: clear()将std :: vector :: capacity()设置为零?
- 为什么在检查null和VB.NET和C#中的值方面有所不同?
- 向非C ++程序员解释C ++ SFINAE