I’m new to ASP.NET Core Web API and I don’t know if this is a simple one but:
I’m working on an ASP.NET Core Web API project and I need to add a new table to the database. There are already existing tables in the database as well. However, I’m not seeing any migration folders in the directory of the project application nor is there a MigrationHistory
in the database so I think the tables where created in the SSMS itself. I created a new model named SampleNewTable1
and I’ve also added it to the existing DbContext
named DataContext
.
When I ran Add-Migration NewMigration -Context DataContext
, it created a new folder Migrations
in the project that included my NewMigration
file and a DataContextModelSnapshot
.
When I ran Update-Database -Context DataContext
It produces this error:
Microsoft.Data.SqlClient.SqlException (0x80131904): There is already an object named 'SampleExistingTable1' in the database.
at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at Microsoft.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean isAsync, Int32 timeout, Boolean asyncWrite)
at Microsoft.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, Boolean sendToPipe, Int32 timeout, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry, String methodName)
at Microsoft.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteNonQuery(RelationalCommandParameterObject parameterObject)
at Microsoft.EntityFrameworkCore.Migrations.MigrationCommand.ExecuteNonQuery(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues)
at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteNonQuery(IEnumerable`1 migrationCommands, IRelationalConnection connection)
at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(String targetMigration)
at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.UpdateDatabase(String targetMigration, String connectionString, String contextType)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabaseImpl(String targetMigration, String connectionString, String contextType)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabase.<>c__DisplayClass0_0.<.ctor>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
ClientConnectionId:<ID>
Error Number:2714,State:6,Class:16
There is already an object named 'SampleExistingTable1' in the database.
The NewMigration
file contains this block of code:
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace SampleApp.Migrations
{
public partial class InitialMigration : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "SampleExistingTable1",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
DataReceived = table.Column<string>(type: "nvarchar(max)", nullable: true),
Transfered = table.Column<int>(type: "int", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_SampleExistingTable1", x => x.Id);
});
migrationBuilder.CreateTable(
name: "SampleExistingTable2",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
DataReceived = table.Column<string>(type: "nvarchar(max)", nullable: true),
Transfered = table.Column<int>(type: "int", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_SampleExistingTable2", x => x.Id);
});
migrationBuilder.CreateTable(
name: "SampleNewTable1",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
DataReceived = table.Column<string>(type: "nvarchar(max)", nullable: true),
Transfered = table.Column<int>(type: "int", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_SampleNewTable1", x => x.Id);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "SampleExistingTable1");
migrationBuilder.DropTable(
name: "SampleExistingTable2");
migrationBuilder.DropTable(
name: "SampleNewTable1");
}
}
}
The Snapshot
contains this auto-generated code:
// <auto-generated />
using System;
using SampleApp.Contexts;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace SampleApp.Migrations
{
[DbContext(typeof(DataContext))]
partial class DataContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "6.0.6")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1);
modelBuilder.Entity("SampleApp.Models.SampleNewTable1", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"), 1L, 1);
b.Property<string>("DataReceived")
.HasColumnType("nvarchar(max)");
b.Property<int?>("Transfered")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("SampleNewTable1", (string)null);
});
modelBuilder.Entity("SampleApp.Models.SampleExistingTable1", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"), 1L, 1);
b.Property<string>("DataReceived")
.HasColumnType("nvarchar(max)");
b.Property<int?>("Transfered")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("SampleExistingTable1", (string)null);
});
modelBuilder.Entity("SampleApp.Models.SampleExistingTable2", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"), 1L, 1);
b.Property<string>("DataReceived")
.HasColumnType("nvarchar(max)");
b.Property<int?>("Transfered")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("SampleExistingTable2", (string)null);
});
#pragma warning restore 612, 618
}
}
}
How do I add a condition to not simply add or update tables depending if it:
- Exists, without new changes to it’s properties. Do Nothing
- Exists, with new changes to it’s properties. Update
- Does not exist. Add
2
Answers
Is there a reason for adding the tables to the database using EntityFramework versus the same way that all previous tables were created (i.e., SSMS)?
I’ve used the Migrations in previous projects and they prove quite useful for code-first implementations where the project was new and the schemas were defined by my code, but I’ve learned that often projects that are utilizing existing databases may find it easier to continue their management of tables and schemas through DBAs.
Could you perhaps provide some additional context as to your required usage of migrations using EntityFramework?
You could check this document related with working with existing database(Notice it was for EF6 not EFCore)
For EFCore ,you could try as below:
1,create Entities and Dbcontext accroding to your current db
2,run
add-migration
then comment all codes inUP
method in migration file like:3,run
update-database
4,modify the entities and dbcontext accroding to your requirement
5,run
add-migration
andupdate-database
againYou could also try to scaffold dbcontext & entities follow this document