I try to use RemoveForeignKey to remove all foreign keys from my DbContext, but it is not usable.
Test DbContext
public class Order
{
public Guid Id { get; set; }
public string Code { get; set; }
public IList<OrderDetail> OrderDetails { get; set; }
}
public class OrderDetail
{
public Guid Id { get; set; }
public Guid OrderId { get; set; }
public int Quantity { get; set; }
}
public class BloggingContextFactory : IDesignTimeDbContextFactory<ConsoleDbContext>
{
public ConsoleDbContext CreateDbContext(string[] args)
{
var optionsBuilder = new DbContextOptionsBuilder<ConsoleDbContext>();
optionsBuilder.UseSqlServer("Server=.;Database=Blogging;Integrated Security=True");
return new ConsoleDbContext(optionsBuilder.Options);
}
}
public class ConsoleDbContext : DbContext
{
public DbSet<Order> Orders { get; set; }
public DbSet<OrderDetail> OrderDetails { get; set; }
public ConsoleDbContext(DbContextOptions<ConsoleDbContext> dbContextOptions) : base(dbContextOptions)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
foreach (var mutableEntityType in modelBuilder.Model.GetEntityTypes())
{
if (mutableEntityType.ClrType == null)
continue;
// delete all foreign key
foreach (var foreignKey in mutableEntityType.GetForeignKeys().ToList())
{
foreignKey.DeclaringEntityType.RemoveForeignKey(foreignKey.Properties, foreignKey.PrincipalKey,
foreignKey.PrincipalEntityType);
}
}
}
}
The foreign key is still in the generated Snapshot.
[DbContext(typeof(ConsoleDbContext))]
partial class ConsoleDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
gma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.2.4-servicing-10062")
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("ConsoleApp.Order", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Code");
b.HasKey("Id");
b.ToTable("Orders");
});
modelBuilder.Entity("ConsoleApp.OrderDetail", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<Guid>("OrderId");
b.Property<int>("Quantity");
b.HasKey("Id");
b.HasIndex("OrderId");
b.ToTable("OrderDetails");
});
modelBuilder.Entity("ConsoleApp.OrderDetail", b =>
{
b.HasOne("ConsoleApp.Order")
.WithMany("OrderDetails")
.HasForeignKey("OrderId")
.OnDelete(DeleteBehavior.Cascade);
});
gma warning restore 612, 618
}
}
EF Core version: .Net Core 2.2
Database Provider: Microsoft.EntityFrameworkCore.SqlServer 2.2.4
Operating system:
IDE: Visual Studio 2019 16.1.1
@chrsas Can you give some details as to why you want to remove all foreign keys from the model?
@ajcvickers The project I am working on was an upgrade of an existing system, which have more than 500 tables and lots of data in the database. The original model is dbfirst, and no foreign keys have been established. In addition to non-standard operations, many data in the system have been unable to establish foreign key constraints. The upgrade cycle is so short that we don't have enough time to clean up the data. Besides, some data are not easy to clean up. For example, product A has been deleted, but in order to prevent audit problems, all relevant sales records cannot be cleared.
So now the fastest way to update the model is to delete the generated foreign keys.
@chrsas "The original model is dbfirst, and no foreign keys have been established." Does this mean there are no foreign key constraints defined in the database, or that they are in the database but not in the EF model?
There are no foreign key constraints defined in the database
@chrsas Thanks for the additional information. So, if I can clarify, the database has no foreign key constraints, but when this was scaffolded into an EF Core model there still ended up being FKs in the model? Or did you create the EF Core model in some other way?
@ajcvickers Thanks for your patience, Sorry for my poor English, My problem is that:
@chrsas For navigation properties to work EF needs there to be FKs in the model. This is because the relationship is represented by the FK, with the navigations acting as a kind of view over the FK.
However, EF doesn't care if these FKs really exist in the database or not. So you can keep them in the model to allow navigation properties to work, but then avoid creating them in the database. There currently isn't any way to configure EF to not create FKs in the migration if they are in the model, but you can manually remove them from the migration, like you said above. So I think what you are doing is the best approach available right now.
@ajcvickers Thanks for your help.
See also #2725, but leaving this as a separate issue since FKs may require a different mechanism.
We are in the same position of having a legacy database with EF Core retrofitted. The requirement for foreign keys removes the ability to use navigation properties with this data, which significantly reduces the benefit of using EF Core.
It would be helpful to have a fluent API method to specify that no foreign keys are required for a given relationship, so that migrations never attempt to create them in the first place.
@zejji I'm curious; if you have a legacy database without FK constraints, but you're using migrations to evolve the schema, then why not add FK constraints as you update the schema?
@ajcvickers - it's a large, monolithic database with many years of data and we don't control the client deployments (i.e. there are multiple installs not under our direct control). Accordingly, right now, we don't want to change the performance characteristics or be forced to go through a data sanitization process - we simply don't have the time budget at the moment as there are hundreds of tables in the database - and we just want to be able to use navigation properties in our code rather than ugly explicit joins. Furthermore, we'd be willing to handle data integrity errors at runtime pending a more complete solution. In an ideal world we would begin from a different starting position but it's very much a brownfield project.
@zejji So what kinds of changes are you making to the database?
@ajcvickers - Features are still being added to the application, which means that any new migrations generally create new tables (which can happily include foreign + unique key constraints because they don't contain any legacy data). The issue is that we want to use EF Core effectively with the old database tables.
@zejji Thanks, understood.
Most helpful comment
We are in the same position of having a legacy database with EF Core retrofitted. The requirement for foreign keys removes the ability to use navigation properties with this data, which significantly reduces the benefit of using EF Core.
It would be helpful to have a fluent API method to specify that no foreign keys are required for a given relationship, so that migrations never attempt to create them in the first place.