EFCore AlterColumn MaxLength in Code First Migration - c#

Using Visual Studio 2019 C#.
I'm very new to a code first development approach.
I've made a working ToDo.cs data model and ApplicationDbContext.cs. I ran PM>add-migration to auto-generate the data migration below and then PM>database-update to commit the table to my SQL Server successfully.
FILENAME: 20200815211807_AddedToDoTable.cs
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace BlazorApp.Data.Migrations
{
public partial class AddedToDoTable : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "ToDoList",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Name = table.Column<string>(maxLength: 15, nullable: false),
Status = table.Column<string>(nullable: false),
DueDate = table.Column<DateTime>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ToDoList", x => x.Id);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "ToDoList");
}
}
}
Now I need to change the string length of the [Name] column from 15 to 25. So, I created a new migration like this:
using Microsoft.EntityFrameworkCore.Migrations;
namespace BlazorApp.Data.Migrations
{
public partial class ChangeNameLength : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("ALTER TABLE ToDoList ALTER COLUMN Name nvarchar(25);");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}
But the Package Manager says: "Object reference not set to an instance of an object." And doesn't make any changes.
What am I doing wrong? Can you help me understand this simple change?
Thanks, Jason

I think my problem had to do with my usage of the Package Manager Console.
I started over using the same migration script and everything worked fine!
PM> add-migration "ChangedNameLength"
Build started...
Build succeeded.
To undo this action, use Remove-Migration.
PM> update-database
Build started...
Build succeeded.
Done.
PM>

Why don't you use the correct migration syntax:
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "ToDoList",
maxLength: 25);
}

Related

Entity Framework Apply Migrations Programatically

I am trying to apply migrations through c# code using entity framework.
I want to drop certain tables(not all of them) and recreate programatically.
I have something like this:
try
{
await dbContext.Database.ExecuteSqlRawAsync("drop table if exists results");
await dbContext.GetInfrastructure().GetService<IMigrator().MigrateAsync("20230104163600_AfterSync");
}
catch (Exception e)
{
throw;
}
I try to run specific custom migration which contains only some of the entities of the DbContext.
Here's the migration:
[DbContext(typeof(TempDbContext))]
[Migration("20230104163600_AfterSync")]
public partial class AfterSync : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "results",
columns: table => new
{
id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
groupId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("pK_results", x => x.id);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "results");
}
}
If I remove the line
await dbContext.Database.ExecuteSqlRawAsync("drop table if exists results");
It says:
Microsoft.Data.SqlClient.SqlException: 'There is already an object named 'results' in the database.'
If I remove the override of Down method in the migration and leave the previous line, the application just crashes.
Can someone help how I can drop and recreate only certain tables not all of them withtout using the database.Migrate() method. Thanks

Ignore property to the IdentityUser in UI

i'm using abp 4.4.2 with razor and i want to ignore the PhoneNumber,i was do this in my EntityExtensionMapping:
OneTimeRunner.Run(() =>
{
ObjectExtensionManager.Instance.MapEfCoreEntity<IdentityUser>(i => i.Ignore("PhoneNumber"));
});
after the adding Migration i have this generated code
public partial class IdentityUpdate : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "PhoneNumber",
table: "AbpUsers");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "PhoneNumber",
table: "AbpUsers",
type: "nvarchar(16)",
maxLength: 16,
nullable: true);
}
}
after the update database, the AbpUsers Table not have the PhoneNumber, However when i want to ignore the field into the user interface in the ModuleExtensionConfigurator,
ObjectExtensionManager.Instance.Modules()
.ConfigureIdentity(identity =>
{
identity.ConfigureUser(user =>
{
user.AddOrUpdateProperty<string>(
"PhoneNumber",
property =>
{
property.UI.OnTable.IsVisible = false;
property.UI.OnCreateForm.IsVisible = false;
property.UI.OnEditForm.IsVisible = false;
});
});
});
The /Identity/Users page and Create/Edit pop-up display again the PhoneNumber.
How can i do ?
Thank you in advance
You need to override the /Identity/Users/index.js file to ignore the PhoneNumber column.
For this create a folder structure like Identity -> Users -> index.js under your Pages folder. Copy and paste the original content of the index.js (that defined in Identity module) file to your index.js file and remove the PhoneNumber column related lines from it.
Check the UI Customization document for more info.
File Structure:
Your index.js file:

EF-Core: Table "name" already exists - when trying to update database

ASP Core 3.1 - API. I'm using the latest version of Entity Framework Core.
I have created a table ToDoItem and a ToDoItemContext. After creating the initial migration, and running update-database. I now have that table in my database. I now added a new model called: ToDoItemDescription.
When I try to update the database after creating a new migration, I get the error:
Table 'todoitems' already exists
Further details: I have two contexts, and this is the command I ran:
update-database -context todoitemscontext
I also tried:
update-database -context todoitemscontext -migration AddDescription
Here is my full code:
Models:
public class TodoItem : IEntity
{
public long Id { get; set; }
public string Name { get; set; }
bool IsComplete { get; set; }
}
public class ToDoItemDescription
{
public int id { get; set; }
public string Description { get; set; }
//public int ToDoItemId { get; set; }
public TodoItem TodoItem { get; set; }
}
Context:
public class TodoItemsContext : DbContext
{
public TodoItemsContext(DbContextOptions<TodoItemsContext> options) : base(options) { }
public DbSet<TodoItem> TodoItems { get; set; }
public DbSet<ToDoItemDescription> TodoItemsDescription { get; set; }
}
Migrations:
[DbContext(typeof(TodoItemsContext))]
partial class TodoItemsContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder) {
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "3.1.9")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
modelBuilder.Entity("project.Models.ToDoItemDescription", b => {
b.Property<int>("id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("Description")
.HasColumnType("longtext CHARACTER SET utf8mb4");
b.Property<long?>("TodoItemId")
.HasColumnType("bigint");
b.HasKey("id");
b.HasIndex("TodoItemId");
b.ToTable("TodoItemsDescription");
});
modelBuilder.Entity("project.Models.TodoItem", b => {
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
b.Property<bool>("IsComplete")
.HasColumnType("tinyint(1)");
b.Property<string>("Name")
.HasColumnType("longtext CHARACTER SET utf8mb4");
b.HasKey("Id");
b.ToTable("TodoItems");
});
modelBuilder.Entity("project.Models.ToDoItemDescription", b =>
{
b.HasOne("project.Models.TodoItem", "TodoItem")
.WithMany()
.HasForeignKey("TodoItemId");
});
#pragma warning restore 612, 618
}
public partial class TodoItems_Initial : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "TodoItems",
columns: table => new
{
Id = table.Column<long>(nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
Name = table.Column<string>(nullable: true),
IsComplete = table.Column<bool>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_TodoItems", x => x.Id);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "TodoItems");
}
}
public partial class AddDescription : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "TodoItemsDescription",
columns: table => new
{
id = table.Column<int>(nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
Description = table.Column<string>(nullable: true),
TodoItemId = table.Column<long>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_TodoItemsDescription", x => x.id);
table.ForeignKey(
name: "FK_TodoItemsDescription_TodoItems_TodoItemId",
column: x => x.TodoItemId,
principalTable: "TodoItems",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateIndex(
name: "IX_TodoItemsDescription_TodoItemId",
table: "TodoItemsDescription",
column: "TodoItemId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "TodoItemsDescription");
}
}
Thank you.
This happens if you have created the database upfront without migrations, for example by using DbContext.Database.EnsureCreated();.
This usually happens when you have a migration that creates a table and the required table is already present in your database so, when you update the database from classes in Migration, it will try to create a table and will fail because the Create command will not be executed as it already has that specific table.
So, in order to avoid the error, you might want to remove the migration class or comment the code in Up() method of that class so it doesn't execute that specific create command.
It could possible help people working with MySQL databases either on Linux and Windows
TL;DR;
I had to rename the table
__efmigrationshistory (note the lowercase) to
__EFMigrationsHistory (note the case)
so the command-line dotnet-ef database update managed to verify all the migrations present on the table __EFMigrationsHistory, and therefore, creating the new field on the table, say Tenant
More
I have to work on Linux, Windows, MacOs boxes. Primarily using Visual Studio code and .net core 3.1.xxx
I use the code-first approach. The MySQL database was firstly, create on the Windows box, where all the tables were created lower cased
Switching to the Linux box, I realized the case was important, so, say, table "tenant" was renamed to "Tenant", by hand.
Once I had to create a new field on the Tenant's c# class, I ran:
dotnet-ef migrations add new-ftpSettings-field and dotnet-ef database update, I got table "Order" already exists. Note I was trying to insert a new field to the "Tenant" table
After a lot of investigation and search, I decided to refresh the database again, and I saw "two suspicious tables" __efmigrationshistory and __EFMigrationsHistory.
I renamed the empty table __EFMigrationsHistory to like Table1 (as a backup), and thus renamed the table __efmigrationshistory to __EFMigrationsHistory
I ran the dotnet-ef database update and the field was properly added to the MySQL database.
*** Like you might have figured this out, running the command-line dotnet-ef database update on Linux was creating a new (and) empty table __EFMigrationsHistory to MySQL database while it had already, a lower cased table on __efmigrationshistory (the good one, created on my Windows box, with all the migrations).
*** This is my first contribution. Any advice is welcome!
Keep safe! Tchau/Au revoir!
I was working through the migration tutorial and had made a mistake sometimes around these steps
dotnet ef migrations add AddBlogCreatedTimestamp
dotnet ef database update
I did the following
deleted the files AddBlogCreatedTimestamp.Designer.cs and AddBlogCreatedTimestamp.cs
inside blogging.db in the table __EFMigrationsHistory i deleted the row that contains 2023__***__AddBlogCreatedTimestamp this was the migration step that failed.
I repeated the migration step dotnet ef migrations add ...
then manually added DropTable(...) to AddBlogCreatedTimestamp.Up()
only then i ran dotnet ef database update
This made sure that in an up-migration the tables would be deleted
Code manually changed
public partial class AddBlogCreatedTimestamp : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
// manually added
migrationBuilder.DropTable(name: "Posts");
migrationBuilder.DropTable(name: "Blogs");
// ... other lines that were created
}
// more other code ...
}
What i still not get is why this is needed. I am not aware to have used anything like EnsureCreated

Generating non-nullable rowversion on SQL Server with EF Core 3.1

We are trying to generate a non-nullable rowversion column on SQL Server with EF Core 3.1 using Fluent API:
public class Person
{
public int Id { get; set; }
public byte[] Timestamp { get; set; }
}
public class PersonEntityConfiguration : IEntityTypeConfiguration<Person>
{
public void Configure(EntityTypeBuilder<Person> builder)
{
builder.HasKey(p => p.Id);
builder.Property(p => p.Timestamp)
.IsRowVersion()
.IsRequired();
}
}
This works fine when the entire table is new:
public partial class PersonMigration : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Persons",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Timestamp = table.Column<byte[]>(rowVersion: true, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Persons", x => x.Id);
});
}
}
However, we sometimes need to add the rowversion to an existing table. In that case, EF Core generates an invalid migration:
public partial class PersonTimestampMigration : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<byte[]>(
name: "Timestamp",
table: "Persons",
rowVersion: true,
nullable: false,
defaultValue: new byte[] { });
}
}
The default value generated above will cause an exception when being applied to the database:
Failed executing DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
ALTER TABLE [Persons] ADD [Timestamp] rowversion NOT NULL DEFAULT 0x;
Microsoft.Data.SqlClient.SqlException (0x80131904): Defaults cannot be created on columns of data type timestamp. Table 'Persons', column 'Timestamp'.
Could not create constraint or index. See previous errors.
Is this a known bug in EF Core? The issue can be fixed by manually removing the defaultValue: new byte[] { } from the migration, but is there a way of suppressing the default value from being generated using the Fluent API?
Is this a known bug in EF Core?
It is bug/defect for sure, but probably not known, since it's happening even in the latest at this time EF Core 5.0 preview. Or is known, but with low priority (for them) - you have to check EF Core Issue Tracker.
Tried adding explicitly .HasDefaultValue(null) and .HasDefaultValueSql(null) - nothing helps, so the only option is manually removing the defaultValue: new byte[] { } from the migration. The good thing is that when you do so, it works and the column is created and populated successfully even though the table has existing records (which is the reason EF Core adds such defaultValue argument for new required columns in general, but as we see shouldn't do that for ROWVERSION).

Entity Framework 7 migration not creating tables

I am working with my first project using Entity Framework 7 and am connecting to a SQL Server where the Database is already created but there are no tables in it yet. I have created my DbContext and created a class, then set a DbSet<> inside my context. I ran the commands to enable migrations and create the first migration, then rand the command to update the database. Everything looked to work fine, no errors came up, but when I look at the database only the EFMigraitonsHistory table was created. When I look at the class that was created for the initial migration it is essentially blank. What am I doing wrong?
Commands I am running:
dnvm install latest -r coreclr
dnx ef migrations add MyFirstMigration
dnx ef database update
Context:
namespace JobSight.DAL
{
public class JobSightDBContext : DbContext
{
public DbSet<NavigationMenu> NavigationMenu { get; set; }
}
}
Table Class:
namespace JobSight.DAL
{
public class NavigationMenu
{
[Required, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Int16 ID { get; set; }
public string ControllerName { get; set; }
public string ActionName { get; set; }
public string ExternalURL { get; set; }
public string Title { get; set; }
public Int16? ParentID { get; set; }
public virtual NavigationMenu Parent { get; set; }
}
}
Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<JobSightDBContext>(options =>
{
options.UseSqlServer(Configuration["Data:JobSightDatabase:ConnectionString"]);
});
}
Class for initial migration (autogenerated by EF):
namespace JobSight.WebUI.Migrations
{
public partial class Initial : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
}
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}
Edit:
After doing what Poke has suggested this is my new auto-generated migration. The table is still not being created at the database level though.
namespace JobSight.WebUI.Migrations
{
public partial class MyFirstMigration : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "NavigationMenu",
columns: table => new
{
ID = table.Column<short>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
ActionName = table.Column<string>(nullable: true),
ControllerName = table.Column<string>(nullable: true),
ExternalURL = table.Column<string>(nullable: true),
ParentID = table.Column<short>(nullable: true),
Title = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_NavigationMenu", x => x.ID);
table.ForeignKey(
name: "FK_NavigationMenu_NavigationMenu_ParentID",
column: x => x.ParentID,
principalTable: "NavigationMenu",
principalColumn: "ID",
onDelete: ReferentialAction.Restrict);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable("NavigationMenu");
}
}
}
You need to set up the entity in your database context first. At the very least, you would need to do this:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<NavigationMenu>();
}
The problem with your migrations was a bit hidden in your project layout. So what you have is a JobSight.DAL project that contains the entities and the database context. And then you have a project JobSight.WebUI which is the actual ASP project containing the Startup.cs with the database setup.
This is causing problems because by default EF will just assume to find everything in the current assembly. So if you are launching the ef command from your web project, it will create the migrations in there even if the context is in another project. But when you’re then trying to apply the migration, EF will not find it since it will only look in the context’s project.
So to fix this, you need to create the migrations in the DAL project. You can do that by specifying the project when you call the ef command:
dnx ef migrations add Example -p JobSight.DAL
You can verify that this worked by running dnx ef migrations list afterwards. This should now return the Example migration; previously, that command didn’t return anything: It could not find a migration which is the reason why the update command only said Done (without applying the migration) and the database wasn’t created. So if you now get the migration there, you can then apply it using:
dnx ef database update
Note that since the migration is now created in the DAL project, you need to add a reference to EntityFramework.MicrosoftSqlServer there, otherwise the project will not compile. You need to do that before you can run the list command above.
Finally, for some more information about this, see this issue.
Although this is not the answer to the original question, I post my answer here because it might help someone who has a similar problem. My problem was also that the tables were not created, but dotnet ef migrations add InitialCreate did create 3 .cs files in the Migrations folder. But dotnet ef database update only created the MigrationsHistory table and dotnet ef migrations list did not return any migrations.
It turned out that the problem was that the Migrations folder was excluded from the Visual Studio project. Once I included it again, everything worked fine.
I had the same problem and this is how I resolved it
I deleted my database in SQL
I changed the name I used for the previous migration. I changed from "Add-Migration InitialCreate" to "Add-Migration NewName"

Categories