15

I just started moving my MVC5 project with EF6x to MVC Core and EF Core but have a big problem with my entities configuration's. How you can migrate a EF6 Fluent configure to EF core?
I need a guide with sample if possible.

Here is one of my mapping classes and my try

EntityMappingConfiguratuin

public interface IEntityMappingConfiguration
{
    void Map(ModelBuilder b);
}

public interface IEntityMappingConfiguration<T> : EntityMappingConfiguration where T : class
{
    void Map(EntityTypeBuilder<T> builder);
}

public abstract class EntityMappingConfiguration<T> : EntityMappingConfiguration<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);
        }
    }
}

DbContext

public class CommerceServiceDbContext : AbpDbContext
    {
        public CommerceServiceDbContext(DbContextOptions<CommerceServiceDbContext> options) 
            : base(options)
        {
        }

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

Simple old configuration

public partial class AffiliateMap : EntityMappingConfiguration<Affiliate>
{
    public override void Map(EntityTypeBuilder<Affiliate> b)
    {
        b.ToTable("Affiliate");
        b.HasKey(a => a.Id);
        b.HasRequired(a => a.Address).WithMany().HasForeignKey(x => x.AddressId).WillCascadeOnDelete(false);
    }
}

My Try

public partial class AffiliateMap : EntityMappingConfiguration<Affiliate>
{
    public override void Map(EntityTypeBuilder<Affiliate> b)
    {
        b.ToTable("Affiliate");
        b.HasKey(a => a.Id);
        b.HasOne(a => a.Address)
            .WithMany().HasForeignKey(x => x.AddressId).IsRequired().OnDelete(DeleteBehavior.Restrict);
    }

}

I've done this using Google Search and Microsoft Documentation. But I'm not sure of my work. Since I have +100 configure classes, I'll ask you before continuing. I apologize if the contents of my question are not compatible with the terms and conditions of the site.

bricelam
  • 28,825
  • 9
  • 92
  • 117
hitasp
  • 698
  • 2
  • 8
  • 19
  • Is there any error you get? – Sefe Mar 07 '18 at 08:41
  • @Sefe No, I removed EF6 NuGet so I cant compile before fixes all of my entities. Just wanted know my try is done or not – hitasp Mar 07 '18 at 08:43
  • 4
    The only conversion tool I know is a human developer. – Gert Arnold Mar 07 '18 at 08:55
  • 1
    Your conversion looks ok. What is concerning you? Do you have a specific question? – Ivan Stoev Mar 07 '18 at 09:01
  • @GertArnold You right. I just started core 2, human developers never asked for true way? Maybe I'm going wrong! It will take me tens of hours . Asking isn't bad, try it – hitasp Mar 07 '18 at 09:02
  • 1
    For a test run you can configure only a part of your entities and the rest later. There is no replacement for trying it yourself. – Sefe Mar 07 '18 at 09:06
  • 1
    Thank you for the time you spent reading my post @IvanStoev – hitasp Mar 07 '18 at 09:09
  • @Sefe True. I created simple project for that. My project haven't Test unit. Maybe is time to add. Thank you. – hitasp Mar 07 '18 at 09:14
  • 1
    Also, note that EF core has different mapping options than EF6. For example, many-to-many with hidden junction class is not supported, but other options have been added, like more ways to model one-to-one associations and using alternate keys. That's probably one of the reasons why automated conversion has never been implemented. – Gert Arnold Mar 07 '18 at 09:21
  • @GertArnold good tips thank you!! Please add this as post with suggestion link – hitasp Mar 07 '18 at 09:26

1 Answers1

22

I found a good article about moving to EF core. I want share that and keeping this question for starters like me.

Code Updates
Namespace System.Data.Entity replaced by Microsoft.EntityFrameworkCore
HasDatabaseGeneratedOption(DatabaseGeneratedOption.None) replaced by ValueGeneratedNever();
The base constructor of DbContext doesn't have a single string parameter for the connection string. We now have to inject the DbContextOptions
OnModelCreating(DbModelBuilder modelBuilder) becomes OnModelCreating(ModelBuilder modelBuilder). Simple change, but change all the same
modelBuilder.Configurations.AddFromAssembly(Assembly.GetExecutingAssembly()); is no longer available which means that EntityTypeConfiguration is also not available, so I had to move all my entity configuration to OnModelCreating
((IObjectContextAdapter)context).ObjectContext.ObjectMaterialized is no longer available. I was using that to extend the DbContext to convert all dates in an out to Utc. I haven't found a replacement for that yet.
ComplexType is no longer available. I had to change the model structure a bit to accomodate this.
MigrateDatabaseToLatestVersion is no longer available so I had to add the below to my startup.cs

using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
    serviceScope.ServiceProvider.GetService<SbDbContext>().Database.Migrate();
}

WillCascadeOnDelete(false) becomes OnDelete(DeleteBehavior.Restrict)
HasOptional is no longer relevant as per post
IDbSet becomes DbSet
DbSet<T>.Add() no longer returns T but EntityEntry<T>

var entry = context.LearningAreaCategories.Add(new LearningAreaCategory());
//that's if you need to use the entity afterwards
var entity = entry.Entity;

IQueryable<T>.Include(Func<>) now returns IIncludableQueryable<T,Y> instead of IQueryable<T>, same applies for OrderBy. What I did was moving all the includes and orderbys to the end.

Source: Moving from EF6 to EF Core

hitasp
  • 698
  • 2
  • 8
  • 19