{“error”:”Entity type ‘AspNetUserRoles’ has composite primary key defined with data annotations. To set composite primary key, use fluent API.”}

When a database table has composite keys (multiple columns are in the key) you cannot use the usual key definition

[Key]
[Display(Name = “UserId”)]
public string UserId { get; set; }

[Key]
[Display(Name = “RoleId”)]
public string RoleId { get; set; }

When you run the application you get the error message:

{“error”:”Entity type ‘AspNetUserRoles’ has composite primary key defined with data annotations. To set composite primary key, use fluent API.”}

To declare composite keys, in the fluent API format

In the model declare the keys

public class AspNetUserRoles {

    // Composite primary keys
    // Initialized in ApplicationDbContext.OnModelCreating()
    public object UserId { get; internal set; }
    public object RoleId { get; internal set; }
    ...

In the ApplicationDbContext file add the lines to the OnModelCreating(ModelBuilder builder) method

// Composite primary key
builder.Entity().HasKey(table => new {
   table.UserId,
   table.RoleId
});

 

 

Generate SQL script from Entity Framework migration script

It is not recommended to execute Entity Framework migration scripts in production, It is important that you execute all SQL steps manually on the production database section-by-section to immediately see the result and be able to recover in case a destructive action goes wrong.

The Visual Studio .NET application templates contain Entity Framework migration scripts to set up your local database to match the sample code. To generate the SQL script you can execute by hand on the production database

Install the EF Core .NET Command-line Tools

  1. Open a command window in the folder of the project that contains the database access code
  2. In the command line execute
    dotnet add package Microsoft.EntityFrameworkCore.Design
    dotnet restore
  3. Test the dotnet ef installation with
    dotnet ef

 

Script the .NET Entity Framework migrations

  1. Open a command window in the folder of the project that contains the database access code
  2. In the command line execute
    1. To generate the SQL script to bring the current development database to the scripted configuration state, use the –idempotent option.
      (Generating idempotent scripts for migration is not currently supported by MySql)

      dotnet ef migrations script --idempotent --output "script.sql" --context MY_DBCONTEXT
    2. To generate the SQL script based on the entire migration script to update the production database to match the template after you have updated the development database
      dotnet ef migrations script --output "script.sql" --context MY_DBCONTEXT

 

 

DbUpdateConcurrencyException: Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded.

The .NET Core Entity framework makes database access easy. When you auto-generate a Razor page in a .NET web application to edit a data row, the scaffolding places controls on the page for every column.

There are columns in most of the tables that we don’t want to display or edit, like keys, checksums, password hashes. If column values are missing during database update, the error is thrown:

A database operation failed while processing the request.
DbUpdateConcurrencyException: Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.

When the edit page is displayed, all values of the row are passed to the page in the Model. When the user clicks the Save button the model is sent back to the server, and the OnPostAsync() method saves the values to the database. The values that we don’t display or store otherwise on the web page are not retained in the browser, and not passed back to the server. To keep the not displayed values, add hidden attributes to the page. The primary key of the row is automatically added, and based on that create hidden attributes for the rest of the not displayed columns.

 <form method="post">
 <div asp-validation-summary="ModelOnly" class="text-danger"></div>
 <input type="hidden" asp-for="ApplicationUser.Id" />
 <input type="hidden" asp-for="ApplicationUser.AccessFailedCount" />
 <input type="hidden" asp-for="ApplicationUser.ConcurrencyStamp" />
 <input type="hidden" asp-for="ApplicationUser.NormalizedEmail" />
 <input type="hidden" asp-for="ApplicationUser.NormalizedUserName" />
 <input type="hidden" asp-for="ApplicationUser.PasswordHash" />
 <input type="hidden" asp-for="ApplicationUser.SecurityStamp" />
 <input type="hidden" asp-for="ApplicationUser.UserName" />