Entity framework migrations ignoring WillCascadeOnDelete - c#

look at this question for example.
Entity Framework (EF) Code First Cascade Delete for One-to-Zero-or-One relationship
I have a normal context etc.
If i change anything, i can generate a new migration per Add-Migration test.
But if i change WillCascadeOnDelete() from true to false or adding some with true it is ignored by entity framework.
I'm using Code first with a generated model from database.
In the generated model everything was on WillCascadeOnDelete(false).
So now I'm changing it from false to true but its ignored by entity framework.
I tried this: http://msdn.microsoft.com/en-us/data/jj591620.aspx#CascadeDelete too.
After adding this lines ... Nothing changes if i add Add-Migration newTest.
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>()
modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>()
This is ignored, too, by Add-Migration thirdTest.
modelBuilder.Conventions.Add<OneToManyCascadeDeleteConvention>()
modelBuilder.Conventions.Add<ManyToManyCascadeDeleteConvention>()
I can change everything with WillCascadeOnDelete... It is ignored!
If i change everything else, it works and would be appended in new Migrations...
The main class for this construct is the following.
[Table("SomeToThing")]
public class SomeToThing : Base
{
[Column("Some")]
public Guid SomeId { get; set; }
[ForeignKey("SomeId")]
public virtual Some Some { get; set; }
[Column("Thing")]
public Guid ThingId { get; set; }
[ForeignKey("ThingId")]
public virtual Thing Thing { get; set; }
}
I have this tables:
Some
SomeToThing
Thing
The SomeToThing has additional variables and because that i can't map Some directly to Thing.

I know this thread is old, but I was just having the same issue.
My solution was to delete the migration source file and re-scaffolding it from scratch.
On my first try I forgot to set .WillCascadeOnDelete(false), and for good reasons, SQL Server rejected the migration due to cycles. Then when I tried to re-scaffold the migration using the same name after removing cascades in the OnModelCreating method, EF just wouldn't pick up those particular changes.
Then I deleted the migration source file and ran Add-Migration SameMigrationName. Cascade deletes were removed, and seems like it worked, since MSSQL accepted the migration script. I'm using EF 6.1.3 btw.

One thing I would like to mention, relating to the problem I was having, was that I added the following code (to my 'OnModelCreating', ie DbContext):
modelBuilder.Entity<MyEntityTwo>()
.HasMany(e => e.MyEntityOne)
.WithRequired(e => e.MyEntityTwo)
.HasForeignKey(e => e.MyEntityTwoId)
.WillCascadeOnDelete(false);
but I added this AFTER the table defining MyEntityOne was already defined, ie in a previous migration.
Turns out that since I added this to OnModelCreating after the table was already defined, entity framework did 'not' pickup the willcascadeondelete(false) when I added a new migration.
To fix this, I had to manually add the following to (new) migration:
DropIndex(...this was created by EF for me already. Not important...);
DropForeignKey("MyEntityOne", "<name of Foreign key goes here ie FK_MyEntityOne_...etc>");
AddForeignKey("MyEntityOne", "MyEntityTwoId", "MyEntityTwo", "Id", cascadeDelete:false);
AlterColumn(...this was created by EF for me already. Not important...);
CreateIndex(...this was created by EF for me already. Not important...);
By adding the AddForeignKey line, with cascadeDelete: false, it will re-apply the foreign key with cacade on delete false this time.

Related

How to add second DbContext to existing EF project

I have an existing Ef DbContext (ApplicationDbContext) that connect to a MySql server with it's proper OnConfiguring and OnModelCreating function.
Now I must add a new DbContext (GeoDbContext) to a different server.
I add the GeoDbContext in services
.AddDbContext<ApplicationDbContext>(m => m.UseMySql(ApplicationConn, ServerVersion.AutoDetect(ApplicationConn)))
.AddDbContext<GeoDbContext>(m => m.UseNpgsql(GeoConn))
In the GeoDbContext, with its own OnConfiguring and OnModelCreating function, I defined a new DbSet property
public DbSet<UserLocation> Locations { get; set; }
Then I exec the Add-Migration , and this is my problem.
Specifying I want to use the GeoDbContext
Add-Migration addLocation -Context GeoDbContext
I receive an error about properties existing in the ApplicationDbContext, already correctly configured in the ApplicationDbContext OnModelCreating function.
The entity type (omissed) has multiple properties with the [Key] attribute. Composite primary keys can only be set using 'HasKey' in 'OnModelCreating'.
I want add a migration only for the GeoDbContext.
How to correctly configure it?
As #KirkWoll wrote in the comment
This usually happens because one or more of the entity types (i.e. UserLocation) has relationship properties (either single or collection) with types that are in the other database.
Remove the navigation property from the model did the work.

EF Core Cascade Delete

Context: Visual Studio, Blazor .NET 5, Azure SQL Server
I have an entity with two FK. If I delete a record in one the FK tables I get the typical Referencing error.
In https://learn.microsoft.com/en-us/ef/core/saving/cascade-delete it seems to say the Cascade Delete is the default.
When I generate a new Migration (add-migration cascade) there is no
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
... attached to the FK properties of the entity in question in the Migration documents generated.
Is there an Attribute that can be applied to the FK property in the entity class?
Is there some other way of doing this in code?
How do I modify the migration documentation to entrench th?
This is what I ended up doing .. I did it in code
public async Task DeleteRound(int Id)
{
var round = _context.Rounds.Where(e => e.Id==Id).Include(e => e.Activitys).First();
_context.Rounds.Remove(round);
await _context.SaveChangesAsync();
}
I had to add the following to the Round Class:
public IList<Activity> Activitys { get; } = new List<Activity>();
No further code required. No need to populate the list as above. It seems that EF is doing it seamlessly. No need to annotate the Migration files.

Entity Framework code-first migrations does not generate a foreign key and ignores the ForeignKey data annotation

I am trying to add a foreign key to my database table using EF code-first migrations, but when I run add-migration, the Up() and Down() methods in the generated migration are empty.
The base table to which the foreign key should link is Reservation and the table to which I am trying to add the key is Batch.
Reservation model class:
public class Reservation
{
[Key]
public int ReservationId { get; set; }
public virtual ICollection<Batch> Batches { get; set; }
...
}
Batch model class:
public class Batch
{
[Key]
public int BatchId { get; set; }
public int ReservationId { get; set; }
[ForeignKey("ReservationId")]
public Reservation Reservation { get; set; }
...
}
The Reservation attribute was previously called TempReservation and did not have a [ForeignKey] annotation which is why the foreign key did not get created in the first place.
I tried fixing it by adding the [ForeignKey] annotation and changing the property name to Reservation like in the above code snippet shows, but to no avail.
The migration always ignores my changes, giving me empty Up() and Down().
I have other model classes that follow the same "structure" and they all have foreign keys without any issues. The only difference is that I am adding this FK after the Batch table was already created.
If you started from scratch, your code model setup should work, so your model looks ok. The problem is that by not using the [ForeignKey] attribute the first time, your database schema now likely has an additional Shadow Property column called Reservation_ReservationId. However as this field isn't an active declaration in your model, it's hard to target directly as your convention configuration can greatly affect this, for instance, if you have configured the appropriate convention, the shadow property
may have already been named ReservationId.
tried fixing it by adding the [ForeignKey] annotation and changing the property name to Reservation like in the above code snippet shows, but to no avail.
As suggested above, the database may have already generated the correct foreign keys in the database, based on public virtual ICollection<Batch> Batches { get; set; }.
Something to remember:
Whenever making changes to the model that rename fields and or modify indexes or relationships on existing fields, you must perform these operations in separate migrations or the migration generation logic can't understand you will have to apply the change manually.
If you do these in one hit, you will almost always have to manually edit the migration file in some way.
after applying your manually modified migration logic to the database, if you now run the add-migration command it should generate an empty migration. If this is the case then you can generally move on.
Instead you could have followed this process:
Rename the navigation property, and any other fields.
Add-Migration... review the generated output
'Update-Database`...
Add the ForeignKey attribute
Add-Migration... review the output, if this is empty, check that the foreign key is not already correctly defined in the database
'Update-Database`... if necessary
Code First Migrations is not perfect out of the box
it is still a very usable tool but you need to review the generated code and add to is as necessary. It is not hard to extend it to support default value declarations, or any SQL DDL management queries when or if you need to.

Entity Framework: why still trying to read from a removed entity in the DbContext?

I have a DbContext with many classes/entities targeting a Firebird database. I used to have an entity named DinnerPasses, which was declared (as all others) using Code First:
public class FreezedOrdersContext : DbContext
{
public FreezedOrdersContext()
: base("name=ConnectionString")
{
}
// The deleted entity... (NOTE: THIS IS NO LONGER IN THE FILE...)
public virtual DbSet<DinnerPass> DinnerPasses { get; set; }
public virtual DbSet<FirebirdFreezedSalesOrder> FreezedSalesOrders { get; set; }
// Other entities, removed for clarity...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
Database.SetInitializer<FreezedOrdersContext>(null);
// Some of the lines still in the file...
modelBuilder.Entity<FirebirdFreezedSalesOrder>().HasKey(p => new { p.ORDERTYPE, p.CUSTOMERTYPE, p.TABLEID, p.SUBORDERNUMBER });
modelBuilder.Entity<FirebirdFreezedSalesOrder>().ToTable("FREEZEDSALESORDER");
// NOTE: This 2 lines are NO LONGER in the file...
modelBuilder.Entity<DinnerPass>().HasKey(p => p.NUMBER);
modelBuilder.Entity<DinnerPass>().ToTable("GENERALINFO");
}
}
The DinnerPasses entity was deleted. Now, reading any of the other entities goes fine, but when I try to save some other entities into the database db.SaveChanges();, I get the following exception:
"Dynamic SQL Error SQL error code = -204 Table unknown DinnerPasses At line 6, column 8"
System.Exception {FirebirdSql.Data.FirebirdClient.FbException}
So, I guess that EF created some model file somewhere that allows it "remember" that entity (and since the line modelBuilder.Entity<DinnerPass>().ToTable("GENERALINFO"); is no longer part of the file, it is trying to get the DinnerPass entity from a table of the same name).
How can I fix this? Where are the model files for this? They are certainly not found anywhere in my project folder...
Thanks in advance.
You need to remove the DbSet and the entity class from your context entirely (including references from other entities!). If you don't specify any additional metadata, then Entity Framework will assume a tablename derived from the entity classname.
Ok, so I found out what happened:
I removed the DinnerPasses entity and replaced it with a new entity called GeneralInfo that was more appropriate (it gets more info from the table, instead of my initial needs that was the Dinner Pass information within that table).
Here is the issue: When I created the new GeneralInfo class, I copied a property from the old DinnerPass class (called FormattedDinnerPasses) into the new GeneralInfo class/entity. When I changed that property to a method, it no longer tried to access the "DinnerPasses" table.
So, I think the problem was having a property that didn't have a backing variable (the property just did a bunch of calculations and returned a list of formatted items). Maybe you can have one but need to give it an attribute indicating that it must be ignored when Entity Framework is binding to the table...

EF migration shows empty Up() Down() methods

I have a local database that is currently in it's second version and should now go to it's third version.
The code for the previous migrations was generated by another programmer so I am assuming I am doing something wrong here.
In my model there are around 30 classes, and inside the model folder there is a mapping folder and it contains the mappings for those 30 classes.
So now I added 1 new class in the same manner as those previous classes and then run the add-migration command in the Package Manager Console.
Infortunately I get an empty migration Up() and Down() method.
When I look in the database there is a __migrationHistory available with the previous 2 migrations. If I run my application now, the third migration is also added but obviously the new table is not being created because it's not in the Up() method.
What could I be doing wrong?
I think something is going wrong when scaffolding the previous migrations... It's like it can't find the new Code-First classes I have added.
This is my command:
add-migration "1.2" -verbose -ProjectName "MyEFproject"
I am assuming that the scaffolding doesn't know where to look for the new class... or is this by convention that all model classes are just expected to be in the project?
Result of add-migration:
namespace MyProject.Migrations
{
using System;
using System.Data.Entity.Migrations;
public partial class _1002 : DbMigration
{
public override void Up()
{
}
public override void Down()
{
}
}
}
Sample of new Model Class:
using System;
using System.Collections.Generic;
namespace MyProject.Models
{
public partial class MyTable
{
public string SomeId { get; set; }
public string SomeText { get; set; }
}
}
Sample of new Mapping class
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
namespace MyProject.Models.Mapping
{
public class MyTableMap : EntityTypeConfiguration<MyTable>
{
public MyTableMap()
{
// Primary Key
this.HasKey(t => t.SomeId);
// Properties
this.Property(t => t.SomeText)
.IsRequired()
.HasMaxLength(30);
// Table & Column Mappings
this.ToTable("MyTable", "database");
this.Property(t => t.SomeId).HasColumnName("SomeId");
this.Property(t => t.SomeText).HasColumnName("SomeText");
}
}
}
Thank you,
You need to add your table to your implementation of the DbContext class, e.g.
public class MyDatabaseEntities : DbContext {
public virtual DbSet<MyTable> MyTable { get; set; }
}
While rolling back an existing EF Core Data Context back to empty, my migrations wouldn't generate until I removed the ApplicationDbContextModelSnapshot that accompanied the migrations.
This class is auto-generated and needs to align with your current migration level.
I was able to fix this issue by deleting a record of last migration from _MigrationHistory table.
This record had been incorrectly created before I added DbSet for new model object to DbContext class.
After this deletion new migration was created with correct Up() and Down() methods.
I had this problem because I forgot to add {get; set;} after my variable names
You need to add your table to your implementation of the DbContext class, e.g. While rolling back an existing EF Core Data Context back to empty, my migrations wouldn't generate until I REMOVED the ApplicationDbContextModelSnapshot that accompanied the migrations.
In my case, the datacontext project is a class lib project. It is different from the startup project which is asp.net mvc 5 project. Now by mistake the connection string in the startup project is pointing to a different database.
So ensure that datacontext project and startup project point to the same database. Also use the full command as mentioned in the question like the following. You can include -Force as well.
add-migration "InitialMigration" -verbose -ProjectName "MyEFproject" -Force
Also: Make sure any new properties you've added are public!
In my case I was doing a migration where I added fields to an existing table and was ending up with empty Up and Down methods,
I had something like this:
public bool ExistingField { get; set; }
bool NewField { get;set; }
Can you spot the difference...?
If you make this mistake rerun the migration with the same name (you probably will need to add the -Force parameter to scaffold it full).
PS. Always make sure your project builds fully before attempting to do any kind of EF command. If your project doesn't already build you're asking for trouble.
You need to add your MyTable in Dbset and your issue will be resolved:
public DbSet<MyTable> MyTables { get; set; }
I was getting empty migrations added when I had mistakenly related two tables using a 1-many relationship rather than a many-many (i.e. i forgot one of the navigation properties). I had a seeding file that was expecting a many-many relationship and was subsequently failing during the migration causing the migration to fail. Unfortunately there was no output that made it obvious that was the problem and it was only by using the Entity Framework Power Tools (v4 but installed in VS2015) did i visually see the incorrect relationship and realize it was probably the cause.
I had to Update-Database with the latest migration before the empty one appending this parameter -TargetMigration:"{your-migration-name}".
Probably it will tell you that there will be data loss from the next buggy one we tried. If you can afford it append -Force to it.
Then I tried to add my new Add-Migration and it wasn't empty.
Final thing that you may need to do if above is throwing exception is to go SQL Server Management Studio and delete the last Automatic migration and try to add it again.
if new tables added to Context
just remove new table in "Migration/ExampleContextModelSnapshot"
I had the same issue on EFcore. When renaming Phone -> mobile, the migration came up empty.
My DbContext :
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MyUser>()
.Property(c => c.Mobile)
.HasColumnName("phone");
}
Problem was using .HasColumnName("phone") was overriding the actual property name so EF probably couldn't see any change.
Changing string value made it work.
I had this exact issue after I wanted to add an extra column to my database. Because my data would not seed unless the tables were empty, I deleted all the tables and the migrations to recreate the tables. When I tried to migrate, the migration had empty up and down methods.
I solved this by deleting the snapshot file as this was creating the issue. So I deleted all the migrations and the snapshot file, added the migration again and ran update database. The tables and migrations were successfully updated with my new column.
A better way to do this though is to run the down method and drop the tables like that if you are working on test data. Obviously this is bad in the real world to drop tables.
To me the problem was that Id property that should correspond to table id was named FeedbackId.
I changed to "Id" and then Up/Down weren't empty anymore.
Dunno if that can help somehow
If your project is small, i.e. you do not have too many migrations yet, you can delete all from your Migration folder. After that, add the migrations again.
I think this also happens when u try to do migration without any changes in the models. eg when you do migration one and succeed, when u try to do migration2 without doing any changes in any of the models, it will create empty UP and Down.
From the perspective of a complete Entity Framework (Core) beginner:
Create your class which will become your table
You can have subclasses with many-to-many or one-to-one relationships.
In step 3 you see the context where both properties have a one-to-one relationship.
Ensure you have one DbContext
If you have more than one DbContext you need to specify which context you want to add the migration to with the -Context parameter.
Add your class to your DbContext as shown by #CondingIntrigue
As a reference The Entity Framework Core DbSet
public class AccountContext : DbContext
{
public DbSet<Account> Accounts { get; set; }
public DbSet<SecretIdentity> SecretIdentity { get; set; }
}
Enter Add-Migration
In my case, I was encountering similar problems with Visual Studio Code.
I have fixed these by doing the following:
Check inside your ContextModelSnapshot : ModelSnapshot
Comment Model Entity Definition…
Delete your migration files related to these entity
Delete the migrations from the dbo.__EFMigrationsHistory table
Compile your solution.
Run the following commands:
dotnet ef migrations add migrationName -p ProjectContainer/
dotnet watch run
Temprorary remove
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
and then do initial create
Add-Migration InitialCreate
If after adding your class in the dbContext and your migration is still empty: do the following:
In your DbContextModelSnapshot class, remove every related code to that class name that you are trying to apply add-migration on. Save the DbContextModelSnapshot.cs and use the Add-Migration "Added_filename"
This work for me.
In my case ,I deleted Migration folder completely. As long as I didn't remove the "ApplicationDbContextModelSnapshot" and all previous migrationas it didn't work.
For me it was because I hadn't add Configuration files.
onModelCreating:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);
}
and add configurations in same assembly derived from IEntityTypeConfiguration<T> where T is your model.
I missed adding
{get;set}
After adding getter and setter, up and down methods are not empty.

Categories