MVC 5 EF - Error when trying to change Table name - c#

I have a class named "Ciudad". When I want to add a migration to create the datatable, EF uses the name "dbo.Ciudads". I actually wanted the name to be "Ciudades" (with an additional 'e') so I changed it manually.
After updating the databse the table dbo.Ciudades was created successfully. I even created a small script to populate it and it run ok.
However, when I want to query "Ciudades" from the context, I get an exception because it tries to query the table "dbo.Ciudads" (without the additional 'e') which doesn't actually exists. It is an InvalidOperationException: "The model backing the 'ApplicationDbContext' context has changed since the database was created"
So I ran "add-migration foo" and it generates the following migration:
public partial class foo : DbMigration
{
public override void Up()
{
RenameTable(name: "dbo.Ciudads", newName: "Ciudades");
}
public override void Down()
{
RenameTable(name: "dbo.Ciudades", newName: "Ciudads");
}
}
It seems strange because in my database I DO have the table exactly as I wanted with the name "Ciudades". Nevertheless, when I try to update the database with this migration, I get the following exception:
System.Data.SqlClient.SqlException (0x80131904): Either the parameter #objname is ambiguous or the claimed #objtype (OBJECT) is wrong.
I imagine I get this exception because the table "Ciudads" doesn't exist. Am I correct?
If so, where it is getting that table from? I did a search on the Entire Solution for the word "ciudads" and nothing came up.

Thanks to #IvanStoev for the solution.
The problem was that I manually changed the table name in the generated migration class. Later I used FluentAPI to specify the name "Ciudades" but it was to late.
As per #IvanStoev suggestion I deleted everything and created the migrations again, but this time using FluentAPI BEFORE creating the migrations. The table was then generated with the name I intended and everything is working fine now.

You can use this approach .
public override void Up()
{
RenameTable("dbo.Ciudads", "Ciudades");
}
public override void Down()
{
RenameTable("dbo.Ciudades", "Ciudads");
}
Or
If you want to specify your table name.You can use fluent API.
modelBuilder.Entity<Department>().ToTable("t_Department");

It's probably worth downloading microsoft SQL server management studio dev edition.

Related

How can I run SQL script in OnModelCreating by EF Core?

My program has an existing SQLite database.
In the new version of the program, it needs to add a column for a feature.
Now the program is made by .NET 6 (WPF) and EF Core 6.
I have to detect whether the new column existed and add it or not.
Here is my code in OnModelCreating to detect the column existed or not:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
var Result = Database.ExecuteSqlRaw("SELECT Count(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='BindDesign' AND COLUMN_NAME='type'");
}
After the code run, it reports this error:
An attempt was made to use the model while it was being created. A DbContext instance cannot be used inside 'OnModelCreating' in any way that makes use of the model that is being created
How can I solve this? Thank you.
You should use migrations to add columns in the database.
If you want to apply migrations on startup you can check if the database needs to be migrated and apply the migration with something like this
if (_context.Database.GetPendingMigrations().Any()) {
await _context.Database.MigrateAsync();
}
Try to Use Different Context for your schema , the error message is clear , you can on use makes use of the model that is being created.
just make another context for your schema .

Entity Framework Core code-first perform additional actions when generating migrations

I want to keep a history of changes made to all of my tables generated by EF Core.
I could do this by manually creating a second model for every model I want duplicated, but I was wondering if there's any way to do this automatically somehow.
What I would want it to do is, every time a migration is generated that includes a CreateTable call, create a duplicate of the table with something like "History" appended to the name, and with an additional column relating to the original record.
I'm not sure what would be the best way to achieve this, as I'm not very experienced with ASP.NET yet. I was thinking of overriding the MigrationBuilder.CreateTable method, but I can't figure out how I'd get the actual migration builder to use my overridden method.
Note that SQL does support Temporal Tables which internally create a second table for you. It has start/end time columns instead of a single column. The database engine maintains this for you (meaning even ad hoc sql queries not through EF are properly tracked into the history table). This is part of the ANSI SQL standard so you might find this easier than rolling your own. You can read more about these on the MSFT documentation page
If I understand it correctly, you want to execute custom SQL script before running the migration.
Well, that is indeed possible.
You will generate the migration as you do now and you'll get something like this:
public partial class MyMigration: Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
//auto-generated mappings
}
}
before the auto-generate call, you could insert your own SQL script like this:
public partial class MyMigration: Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("CREATE TABLE Customers_History (CustomerName, City, Country)");
migrationBuilder.Sql("INSERT INTO Customers_History (CustomerName, City, Country) SELECT CustomerName, City, Country FROM Customers)");
//auto-generated mappings
}
}
This is just an example, but you can add your own SQL to match your scenario.
With this solution you are not required to create additional models.

Create table and insert data into it during EF code first migration

I'm using Entity Framework Code First with Code First migrations.
During a migration, I need to create a new table, and then insert some data into it.
So I create the table with :
CreateTable("MySchema.MyNewTable",
c => new
{
MYCOLUMNID = c.Int(nullable: false, identity: true),
MYCOLUMNNAME = c.String(),
})
.PrimaryKey(t => t.MYCOLUMNID);
Then I try to insert data with :
using (var context = new MyContext())
{
context.MyNewTableDbSet.AddOrUpdate(new[]
{
new MyNewTable
{
MYCOLUMNNAME = "Test"
}
});
context.SaveChanges();
}
But I get an error :
Invalid object name 'mySchema.MyNewTable'.
Is it possible to do what I need ? Create a table and inserto data into it in the same migration ?
I already have other migrations where I create tables or insert data into a table, but never in the same migration...
My recommendation is move that insert code to the Seed method. Migrations introduced its own Seed method on the DbMigrationsConfiguration class. This Seed method is different from the database initializer Seed method in two important ways:
It runs whenever the Update-Database PowerShell command is executed.
Unless the Migrations initializer is being used the Migrations Seed
method will not be executed when your application starts.
It must handle cases where the database already contains data because
Migrations is evolving the database rather than dropping and
recreating it.
For that last reason it is useful to use the AddOrUpdate extension method in the Seed method. AddOrUpdate can check whether or not an entity already exists in the database and then either insert a new entity if it doesn’t already exist or update the existing entity if it does exist.
So, try to run the script that you want this way:
Update-Database –TargetMigration: ScriptName
And the Seed method will do the job of inserting data.
As Julie Lerman said on her blog:
The job of AddOrUpdate is to ensure that you don’t create duplicates
when you seed data during development.
You can try this approach:
after creating table,
create another empty migration in your Package Manager Console using:
Add-Migration "MigrationName"
Then open the .cs file of that migration and, in Up() method, insert this code:
Sql("INSERT INTO MyNewTable(NyColumnName) Values('Test')");
After that, save and go back to Package Manager Console and update the database using:
Update-Database
A way to do "random" things in migrations is to use the Sql method and pass whatever SQL statement you need to perform, for example, inserting data.
This is the best approach if you want your migrations to be able to generate a complete migration SQL script, including your data operations (the Seed method can only be executed in code and won't generate any sql script).
For those who looking for EF Core solution, In the Up method, and after creating the table:
i.e: migrationBuilder.CreateTable(name: "MyTable", .....
add the following code:
migrationBuilder.InsertData(table: "MyTable", column: "MyColumn", value: "MyValue");
or
migrationBuilder.InsertData(table: "MyTable", columns: ..., values: ...);
For more information see the docs: MigrationBuilder.InsertData Method
First I run the
PM> Add-Migration MyTableInsertInto
then I got following,
**The Designer Code for this migration file includes a snapshot of your current Code First model. This snapshot is used to calculate the changes to your model when you scaffold the next migration. If you make additional changes to your model that you want to include in this migration, then you can re-scaffold it by running 'Add-Migration MyTableInsertInto' again.
**
I have used following code for c# data migrations
public partial class MyTableInsertInto : DbMigration
{
public override void Up()
{
Sql("INSERT INTO MyNewTable(MyColumnName) Values ('Test')");
}
public override void Down()
{
Sql("DELETE MyNewTable WHERE MyColumnName= 'Test'");
}
}
Then I run following
PM> update-database
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
Applying explicit migrations: [202204120936266_MyNewTableInsertInto].
Applying explicit migration: 202204120936266_MyNewTableInsertInto.
Running Seed method.
After running the seed method data base is updated successfully and this works fine for me.

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.

Entity Framwork 5 won't use my view

I created an MVC 4 application using EF (Code First) which mapped to a mixture of tables and views which I created using SQL Management Studio which worked fine.
I have started a new MVC 4 project in much the same way as the first, using a completely different database, but this time anytime I try to use a model which maps to a view (not a table), an exception is raised saying that "An object with the name xxx already exists". The SQL profiler shows that EF is trying to create a table for my model.
I find that if I drop the views, let EF create the tables from the models, then delete the tables and replace them with view manually, the application will work for about 2 minutes, reading and using the information from my view, but eventually throwing the same exception.
I have no idea what is going on here.
The code that causes the exception is:
repository.Customers.OrderBy(c => c.AccountNumber);
where the model is:
public class Customer
{
public int Id {get;set;}
public string AccountNumber {get;set;}
public string Name {get;set;}
}
OK - the possible cause of this issue is hiding in your context file. There is probably a statement similar to the one below that is trying to update your database when the model changes.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer<MyContext>(new DropCreateDatabaseIfModelChanges<MyContext>());
}
I generally don't use this method. I prefer to delete the database and re-generate it using the package manager console. (Check out the update-database method of the package manager console)
Using Greg's hint I was able to arrive at the point where I simply added:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer<MyContext>(null);
}
to the context class and this has solved the issue. My understanding here is that I have told EF to do no initialisation, essentially having it map to an existing database that is maintained outside of the code first context.
I have voted up Greg's response as it was the help I needed but creating a new answer as it was the above that solved it eventually. I hope this was done right.

Categories