Add-Migration generates different migrations in VS2017 vs. VS2015 - entity-framework

We recently moved from VS2015 to VS2017 for our EF Code First application. Some of the developers on the team (but not all) get different results calling Add-Migration on VS2015 and VS2017.
For instance, if I generate a migration on VS2015 with no outstanding model changes and a fresh build I get the expected empty migration
Add-Migration ... -Name ShouldBeAnEmptyMigration
gives me:
namespace Blah.Foo.DataModel.Migrations
{
using System;
using System.Data.Entity.Migrations;
public partial class ShouldBeAnEmptyMigration: DbMigration
{
public override void Up()
{
}
public override void Down()
{
}
}
}
If I roll those changes back and run the same command against the same database from VS2017 I get a migration full of unwanted changes:
namespace Blah.Foo.DataModel.Migrations
{
using System;
using System.Data.Entity.Migrations;
public partial class ShouldBeAnEmptyMigration: DbMigration
{
public override void Up()
{
// For some reason EF is trying to add foreign key columns that
// already exist except with an additional suffix of "1".
// e.g. We already have an FK from 'Child' to 'Parent' using
// Guid Parent_Id which has been in place for (literally) years.
// There are 11 such columns it is trying to add here.
// Some date base a couple years, some are more recent.
// I don't see a pattern for which columns it is choosing
// 11 of these, one for each "new" column ...
DropForeignKey("Child", "Parent_Id", "Parent");
...
// 11 of these ...
DropIndex("Child", new[] { "Parent_Id" });
...
// 11 of these ...
AddColumn("Child", "Parent_Id1", c => c.Guid(nullable: false));
...
// 11 of these ...
CreateIndex("Child", "Parent_Id1");
...
// 11 of these ...
AddForeignKey("Child", "Parent_Id1", "Parent", "Id");
...
}
public override void Down()
{
// similar set of DropForeignKey, DropIndex, DropColumn,
// CreateIndex, AddForeignKey
}
}
}
Note that there are no recent changes to most of the DataModels affected.
Currently I am forced to create all my migrations on VS2015. Is there any way to make VS2017 "behave"?
Versions:
Visual Studio Pro 2015 (14.0.25431.01 Update 3)
Visual Studio Pro 2017 (15.9.7)
EntityFramework.6.2.0

Related

Unable to add migrations to EF Core on Azure Function

I have an Azure function running on .NET Core 3.1. I have a .NET Standard 2.1 library that contains an EF Core 3.1 DbContext.
I'm trying to add migrations from Visual Studio and I'm getting the following errors:
If I run PM> Add-Migration Initial selecting as default the function project I get the error 'No DbContext was found in assembly 'SimonApp' (this is my function project). Ensure that you're using the correct assembly and that the type is neither abstract nor generic.'
If I run the same command against the library where EF Core is installed, I get No parameterless constructor defined for type 'SimonApp.Core.Data.ClinikoEntitiesContext'.
I have found lots of posts and questions that are similar on SO but none of them fix my problem.
I have tried creating a parameterless constructor on the context without luck, I get the same errors. My context looks like this:
public class ClinikoEntitiesContext : DbContext
{
public ClinikoEntitiesContext()
{}
public ClinikoEntitiesContext(DbContextOptions<ClinikoEntitiesContext> options)
: base(options)
{ }
My Startup.cs looks like:
class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
var configuration = builder.Services.BuildServiceProvider().GetService<IConfiguration>();
var IsDevelopment = Environment.GetEnvironmentVariable("AZURE_FUNCTIONS_ENVIRONMENT")?.Equals("Development", StringComparison.OrdinalIgnoreCase);
var connString = configuration.GetConnectionString("SqlCliniko");
builder.Services.AddDbContext<ClinikoEntitiesContext>(options => options.UseSqlServer(connString)
.UseLazyLoadingProxies()
.EnableSensitiveDataLogging(IsDevelopment.HasValue && IsDevelopment.Value == true));
builder.Services.AddLogging(loggingBuilder =>
{
loggingBuilder.AddConsole()
.AddFilter(DbLoggerCategory.Database.Command.Name, LogLevel.Warning);
});
}
}

Cannot update identity column "PartyID"

I upgraded project .net core sdk 2.2 to .net core sdk 3.1. My project is working well with .net core sdk 2.2. Party class exist in my project, I get that "Cannot update identity column "PartyID"" when I try to update party name. PartyID is primary key and increment by one by in sql table. Have you any idea?
public class Parties
{
public Parties()
{
}
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public int PartyID { get; set; }
}
Also, I researched this error on web and I added below code.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var partiesBuilder = modelBuilder.Entity<Parties>();
partiesBuilder.Property(p => p.PartyID).Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Ignore);
partiesBuilder.Property(p => p.PartyID).UseSqlServerIdentityColumn();
partiesBuilder.Property(p => p.PartyID).ValueGeneratedOnAdd();
}
However I get this error :
"System.InvalidOperationException: 'The property 'PartyID' on entity type 'Parties' must be marked as read-only after it has been saved because it is part of a key. Key properties are always read-only once an entity has been saved for the first time.'".
Also I used this package:
EntityFramework version 6.4.4, Microsoft.EntityFrameworkCore version 3.1.6

How to Customize Migration History Table with Entity Framework Core

I'm setting up Entity Framework Core in a new API to deploy to an existing SQL Server database that is used by Entity Framework 4.6 applications. There is one Migration History table that is shared by other applications, and has 2 fields in it that need to be populated for each entry: ContextKey, and Model. Entity Framework Core does not have a Context Key, and does not save the Model to the Migration History table.
I've already created a HistoryRepository : SqlServerHistoryRepository and configured Entity Framework Core to use it, but the ConfigureTable method only allows you to create additional columns, but not actually populate each record as it gets inserted with custom data. Providing a default value to the column is not a solution.
public class HistoryRepository : SqlServerHistoryRepository
{
public HistoryRepository(HistoryRepositoryDependencies dependencies)
: base(dependencies)
{
}
protected override void ConfigureTable(EntityTypeBuilder<HistoryRow> history)
{
base.ConfigureTable(history);
history.Property<string>("ContextKey")
.HasMaxLength(300);
history.Property<byte[]>("Model");
}
}
services.AddDbContext<MDSContext>(options =>
options.UseLazyLoadingProxies()
.UseSqlServer(
connectionString,
x => x.MigrationsHistoryTable("__MigrationHistory")).ReplaceService<Microsoft.EntityFrameworkCore.Migrations.IHistoryRepository, Burkhart.CoreServices.IncomingOrders.Core.Models.Base.HistoryRepository>()
);
I should be able to provide a custom value for ContextKey and Model dynamically
I looked all over for solutions, but they all show you how to add a column and set a default value, but not how to set a value dynamically. I ended up digging into the ASP.NET Entity Framework Core source code at GitHub for the solution, so that I would share it with everyone else, as I know there are others that are looking for this information:
Just override the GetInsertScript method on the HistoryRepository and insert your custom values. Here is the full solution:
public class HistoryRepository : SqlServerHistoryRepository
{
public HistoryRepository(HistoryRepositoryDependencies dependencies)
: base(dependencies)
{
}
protected override void ConfigureTable(EntityTypeBuilder<HistoryRow> history)
{
base.ConfigureTable(history);
history.Property<string>("ContextKey")
.HasMaxLength(300);
history.Property<byte[]>("Model");
}
public override string GetInsertScript(HistoryRow row)
{
var stringTypeMapping = Dependencies.TypeMappingSource.GetMapping(typeof(string));
return new StringBuilder().Append("INSERT INTO ")
.Append(SqlGenerationHelper.DelimitIdentifier(TableName, TableSchema))
.Append(" (")
.Append(SqlGenerationHelper.DelimitIdentifier(MigrationIdColumnName))
.Append(", ")
.Append(SqlGenerationHelper.DelimitIdentifier(ProductVersionColumnName))
.Append(", [ContextKey], [Model])")
.Append("VALUES (")
.Append(stringTypeMapping.GenerateSqlLiteral(row.MigrationId))
.Append(", ")
.Append(stringTypeMapping.GenerateSqlLiteral(row.ProductVersion))
.Append($", '{ContextConstants.ContextName}.{ContextConstants.ContextSchemaName}', 0x)")
.AppendLine(SqlGenerationHelper.StatementTerminator)
.ToString();
}
}
Here is a link to the source code on github:
https://github.com/aspnet/EntityFrameworkCore/blob/master/src/EFCore.Relational/Migrations/HistoryRepository.cs

How add a migration to a EntityFramework 7 project

I'm starting a new project using asp.net 5 and EF 7 VS2015.
I selected the project template with the user mangagement.
Now I want to add some classes to the dbContext and have a new schema created with my new classes.
This is wat my ApplicationDbContext looks like:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public DbSet<Candidate> Candidates { get; set; }
public DbSet<Manager> Managers { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
builder.Entity<Candidate>().Key(x => x.Id);
builder.Entity<Manager>().Key(x => x.Id);
}
}
I have not been able to recreate or migrate my database to a version with my Candidates and Managers table.
Which commands do I have to enter where to make my DB appear? My friend Google and Bing have pointed me in every direction, but none of the things I found worked.
You need to use the new dnx commands, for example:
dnx . ef migration add NameOfMigration
And to run the migration:
dnx . ef migration apply
I found this CodeProject article that shows how to deal with migration on ASP .NET 5 project but in summary you need to apply the commands that #DavidG recommended in his answer.
I know this is not your case, but if you were working with a Class Library project, then the commands you would need to run are these:
Open the Package Manager Console:
Run Add-Migration MigrationName If it is the first time, it will to scaffold a migration to create the initial set of tables for your model, otherwise it will scaffold the next migration based on changes you have made to your model since the last migration was created.
Run Apply-Migration to apply the new migration to the database.
If your database doesn’t exist yet, it will be created for you
before the migration is applied.
To apply these commands you need to configure a database provider first. You can do this by overriding OnConfiguring in your DbContext class or in the AddDbContext method when setting up services.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(#"Server=(localdb)\mssqllocaldb;Database=EFGetStarted.ConsoleApp;Trusted_Connection=True;");
}
As per ASP.NET 5 and Entity 7 RC1 the steps would be:
Add a dependency to the Entity Commands nuget package in your main project. So in your project.json you should see this dependency
"EntityFramework.Commands": "7.0.0-rc1-final"
Add an alias command to use from console later on. So in your project.json you would have the following ef command:
"commands": {
"ef": "EntityFramework.Commands",
"web": "Microsoft.AspNet.Server.Kestrel"
}
Open a console and run the migration commands. For example:
D:\Projects\MyProject\src\MyProject.Web.Api>dnx ef migrations add Initial --targetProject MyProject.Data.SqlServer
Then review the Migration that ef will create in your project and apply the changes to your database (the database that is configured for your project) with the following command:
D:\Projects\MyProject\src\MyProject.Web.Api>dnx ef database update
Notice that the attribute --targetProject allows you to specify the project where your DbContext is and where the folder Migrations would be created. If your DbContext is in your main project you can omit that (but I recommend to have a class library project for everything persistance related so this command would be handy)
In your Startup.cs is where you usually would have the configuration for Entity including the connection string. This is a basic example:
public Startup(IHostingEnvironment env)
{
// Set up configuration sources.
var builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; private set; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<KuneDbContext>(options => {
options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]);
});
// Add identity here http://docs.asp.net/en/latest/tutorials/your-first-aspnet-application.html
services.AddMvc();
// Add application services
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// For more details on creating database during deployment see http://go.microsoft.com/fwlink/?LinkID=615859
try
{
using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>()
.CreateScope())
{
serviceScope.ServiceProvider.GetService<KuneDbContext>()
.Database.Migrate();
}
}
catch { }
}
app.UseIISPlatformHandler();
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
//Seed Data if you want to load some test data in the DB
//SeedData.Initialize(app.ApplicationServices);
}
// Entry point for the application.
public static void Main(string[] args) => WebApplication.Run<Startup>(args);
}

Entity Framework 5 Generates SQL Referencing NotMapped Property

I just set about updating a project from Entity Framework 4.3.1 and .NET 4 to Entity Framework 5.0 and .NET 4.5. I updated the .NET version first, and ensured that I'm referencing EF 5.0.0.0 rather than the .NET 4 compatible 4.4.0.0.
I have a class structure like
public class MyBase
{
[NotMapped]
public bool MyProperty { get; set; }
}
public class MyDefinition : MyBase
{
// Some other properties
}
When I attempt to load some MyDefinition instances
using (MyContext ctx = new MyContext())
{
ctx.Configuration.AutoDetectChangesEnabled = false;
ctx.Configuration.LazyLoadingEnabled = false;
ctx.Configuration.ProxyCreationEnabled = false;
var defs = from def in ctx.MyDefinitions.AsNoTracking() select def;
foreach (MyDefinition def in defs) // <-- Exception here
{
// Do stuff
}
}
I get a SqlException
Invalid column name 'MyProperty'.
It is as if NotMapped is respected for purposes of determining whether the existing schema is valid, but the SELECT generated by EF 5 expects there to be a MyProperty column.
The base class and derived class are defined in different assemblies. Both assemblies were carefully checked to ensure they reference EF 5.0.0.0 and target .NET 4.5.
Intellisense claims that NotMapped is System.ComponentModel.DataAnnotations.Schema.NotMapped
How can I prevent EF 5 from selecting that non-existent column?
Add this
using System.ComponentModel.DataAnnotations.Schema
D'oh!
I also updated to VS 2012 today. Something unrelated broke with a post-build event, which caused an earlier version of the assembly containing the base class to be available to the derived class. Fixing the post build event resolved the issue.