C# cannot update database with Entity Framework - c#

I have a problem, unfortunately I can not fix it and can not find a proper solution to this.
Does anyone know what the problem is?
I am trying to update my Tours object with a new TravelCountry.
Migration Code:
migrationBuilder.DropColumn(
name: "TravelCountry",
table: "Tours");
migrationBuilder.AddColumn<int>(
name: "TravelCountryId",
table: "Tours",
type: "int",
nullable: false,
defaultValue: 0);
migrationBuilder.CreateTable(
name: "TravelCountries",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
Name = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4")
},
constraints: table =>
{
table.PrimaryKey("PK_TravelCountries", x => x.Id);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateIndex(
name: "IX_Tours_TravelCountryId",
table: "Tours",
column: "TravelCountryId");
migrationBuilder.AddForeignKey(
name: "FK_Tours_TravelCountries_TravelCountryId",
table: "Tours",
column: "TravelCountryId",
principalTable: "TravelCountries",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
It fails at "migraitonBuilder.AddForeignKey" with the error:
Cannot add or update a child row: a foreign key constraint fails (gam_db.#sql-1e1c_fe, CONSTRAINT FK_Tours_TravelCountries_TravelCountryId FOREIGN KEY (TravelCountryId) REFERENCES travelcountries (Id) ON DELETE CASCADE)
Heres my Tour object:
public class Tour
{
[Key]
public int Id { get; set; }
[Required]
public TravelCountry? TravelCountry { get; set; }
}
And here is my TravelCountry object:
public class TravelCountry
{
[Key]
public int Id { get; set; }
[Required]
public string? Name { get; set; }
}

you need to add a foreign key to your tour model in order to create a relationship between this twp tables
for example:
public int? CategoryId { get; set; }
[ForeignKey("TravelCountryId")]
also make sure you have all the nugets and dont forget the command update-database in console package manger after adding the migrations

Just one question: why is the entity column [required] whilst the variable in the code can be null? Maybe delete the question marks in the declarations because [required] means that this value cannot be null

Related

How to use custom property name for foreign key column in Entity Framework

I for some reason cannot seem to find this info anywhere, but feel this would be a common thing. I originally had this class:
public class SiteSharingPermission
{
[Required]
public Guid Id { get; set; }
public Guid OrganizationId { get; set; }
public Organization Organization { get; set; }
}
I recently needed to modify this column / property (OrganizationId -> PartnerOrganizationId) but I'm having an issue with my migrations on updating the foreign key column property name.
I tried running migrations, modified the up/down to this:
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_SiteSharingPermissions_Organizations_OrganizationId",
table: "SiteSharingPermissions");
migrationBuilder.RenameColumn(
name: "OrganizationId",
table: "SiteSharingPermissions",
newName: "PartnerOrganizationId");
migrationBuilder.AddForeignKey(
name: "FK_SiteSharingPermissions_Organizations_PartnerOrganizationId",
table: "SiteSharingPermissions",
column: "PartnerOrganizationId",
principalTable: "Organizations",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_SiteSharingPermissions_Organizations_PartnerOrganizationId",
table: "SiteSharingPermissions");
migrationBuilder.RenameColumn(
name: "PartnerOrganizationId",
table: "SiteSharingPermissions",
newName: "OrganizationId");
migrationBuilder.AddForeignKey(
name: "FK_SiteSharingPermissions_Organizations_OrganizationId",
table: "SiteSharingPermissions",
column: "OrganizationId",
principalTable: "Organizations",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
But I keep getting an error when trying to get results from this table:
Unknown column 's.OrganizationId' in field list
Any ideas?
I personally won't prefer making changes to migration file. Instead do something like below.
public class SiteSharingPermission
{
[Required]
public Guid Id { get; set; }
public Guid PartnerOrganizationId { get; set; }
[ForeignKey("PartnerOrganizationId")]
public Organization Organization { get; set; }
}
You can also do it using Fluent API method.

EF Core: duplicated foreign key in migration

It's my first project with using Entity Framework Core and sometimes the relationships are a bit confusing for me. The problem is when I'm creating a database migration, it always add foreign keys I haven't defined. So I can't use the database because inserting new values throws a duplicated entry exception.
But first some code of my config:
public class User : IdentityUser
{
public virtual List<SignatureToUser> Signatures { get; set; }
}
public class SignatureToUser
{
[Key]
[Required]
public int SignatureToUserID { get; set; }
public int SignatureID { get; set; }
[Required]
[ForeignKey("SignatureID")]
public virtual Signature Signature { get; set; }
public string SignatureUserID { get; set; }
[Required]
[ForeignKey("SignatureUserID")]
public virtual User User { get; set; }
}
And that is the builder options I use
modelBuilder.Entity<SignatureToUser>().HasOne(l => l.User).WithOne().OnDelete(DeleteBehavior.ClientNoAction);
modelBuilder.Entity<SignatureToUser>().HasOne(l => l.Signature).WithOne().OnDelete(DeleteBehavior.ClientNoAction);
modelBuilder.Entity<SignatureToUser>().HasIndex(l => l.SignatureUserID).IsUnique(false);
modelBuilder.Entity<SignatureToUser>().HasIndex(l => l.SignatureID).IsUnique(false);
And now the problem: this is the generated migration:
migrationBuilder.CreateTable(
name: "SignatureToUser",
columns: table => new
{
SignatureToUserID = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
SignatureID = table.Column<int>(type: "int", nullable: false),
SignatureUserID = table.Column<string>(type: "nvarchar(450)", nullable: false),
UserId = table.Column<string>(type: "nvarchar(450)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_SignatureToUser", x => x.SignatureToUserID);
table.ForeignKey(
name: "FK_SignatureToUser_AspNetUsers_SignatureUserID",
column: x => x.SignatureUserID,
principalTable: "AspNetUsers",
principalColumn: "Id");
table.ForeignKey(
name: "FK_SignatureToUser_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
As you can see there is a foreign key UserId added as a duplicate to my already existing key SignatureUserID.
How can I disable the creation of this additional foreign key?
In my research, I also heard about base classes could be a problem. Is this still a problem? I also tried something like that to trick the base class, but there were no changes.
public class User : IdentityUser
{
[Key]
public string Id { get { return base.Id; } set { base.Id = value; } }
}
Thank you for reading :) I hope anyone has an idea

Foreign Key Issues with Application User

I am using entity framework core and code first to make some tables.
I want one table with two Foreign keys, with both being the application user.
I have it built and running, but every time I try to add to the table I get an error
SqlException: Violation of PRIMARY KEY constraint 'PK_ApplicationUser'. Cannot insert duplicate key in object 'dbo.ApplicationUser'. The duplicate key value is (ef20a79d-e819-499d-b006-c32f5cf85577).
This might just be a database design issue, but I feel like that I am doing this should work.
Here is the models:
public class Test
{
public string TestId { get; set; }
[ForeignKey("Giver")]
public string GiverId { get; set; }
public virtual ApplicationUser Giver { get; set; }
[ForeignKey("Getter")]
public string GetterId { get; set; }
public virtual ApplicationUser Getter { get; set; }
}
// Add profile data for application users by adding properties to the ApplicationUser class
public class ApplicationUser : IdentityUser
{
[InverseProperty("Giver")]
public ICollection<CustomModels.Test> Giver { get; set; }
[InverseProperty("Getter")]
public ICollection<CustomModels.Test> Getter { get; set; }
}
Here is the code to create the table:
migrationBuilder.CreateTable(
name: "Tests",
columns: table => new
{
TestId = table.Column<string>(nullable: false),
GetterId = table.Column<string>(nullable: true),
GiverId = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Tests", x => x.TestId);
table.ForeignKey(
name: "FK_Tests_ApplicationUser_GetterId",
column: x => x.GetterId,
principalTable: "ApplicationUser",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_Tests_ApplicationUser_GiverId",
column: x => x.GiverId,
principalTable: "ApplicationUser",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateIndex(
name: "IX_Tests_GetterId",
table: "Tests",
column: "GetterId");
migrationBuilder.CreateIndex(
name: "IX_Tests_GiverId",
table: "Tests",
column: "GiverId");
This is how I am adding to the DB:
Test test = (new Test
{
Giver = await _userManager.GetUserAsync(User),
Getter = await _userManager.Users.FirstOrDefaultAsync(u => u.Email == "s#gmail.com")
});
_context.Tests.Add(test);
await _context.SaveChangesAsync();
I would like to be able to track which user is giving information and which user is getting information.
We were using just the user email for tracking, but we would have to search for the email every time and I feel like this would be a better long-term solution.
I should be able to add as my "test" rows and repeat users, ie user1 can give to user2 and vise-versa, and that would be 2 different rows.
My guess is _userManager.GetUserAsync(User) isn't operating on the same DbContext as _context. So _context isn't aware of that ApplicationUser and will try to create it. The resolution to this would be to Attach the ApplicationUser before saving.

.NET Core creating non-nullable FK constraint with IdentityUser

I am trying to create a relationship from my main IdentityUser to another class, using the EF migrations in .NET Core 2.2. There is an issue I am running into, and that is the migrations are being created with a null FK constraint. This is something I do not want.
I fear, that I should not be manually editing the migration file (to fix this issue), as when I change these models in the future, my manual edit will be overwritten (because my classes are somehow coded incorrectly).
These are the classes I have..
public class ApplicationUser : IdentityUser
{
public List<Purchase> Purchases { get; set; }
}
public class Purchase
{
public int Id { get; set; }
// others
}
The resulting migration file has a nullable: true property set on ApplicationUserId
migrationBuilder.CreateTable(
name: "Purchase",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
ApplicationUserId = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Purchase", x => x.Id);
table.ForeignKey(
name: "FK_Purchase_AspNetUsers_ApplicationUserId",
column: x => x.ApplicationUserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
Not correct. So, I add properties in the Purchase class (like I have in other POCOs in my project)..
public class Purchase
{
public int Id { get; set; }
// others
public int ApplicationUserId { get; set; }
public ApplicationUser ApplicationUser { get; set; }
}
and re-run the migration regeneration..
migrationBuilder.CreateTable(
name: "Purchase",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
ApplicationUserId = table.Column<int>(nullable: false),
ApplicationUserId1 = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Purchase", x => x.Id);
table.ForeignKey(
name: "FK_Purchase_AspNetUsers_ApplicationUserId1",
column: x => x.ApplicationUserId1,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
I now get the proper non-nullable constraint, but it is a duplicate. (There is a 1 tacked on). My questions are:
Is it safe for me to simply modify the migration file and call it a day?
How can I create a relationship between my ApplicationUser and Purchase classes so the migration file that is generated gives me a non-nullable FK constraint?
1) You can, but each consequent migration will remake this field an d cause you to have an issue. Also since the data type does not match it will not work as expected
2) The id type of the foreign key is wrong. Application user has a primary key of type string but you are using int so it is failing to recognize the correct foreign key.
After you correct that, put the Required attribute on the class. So the final class would look like
using System.ComponentModel.DataAnnotations;
public class Purchase
{
public int Id { get; set; }
// others
[Required]
public string ApplicationUserId { get; set; }
public ApplicationUser ApplicationUser { get; set; }
}
You can generate the migration script using the Add-Migration command, after that you can edit the migration source code and add at least 1 record right after the creation of the new table using:
migrationBuilder.InsertData(
table: "Organizations",
columns: new[] { "OrganizationName", "IsDeleted" },
values: new object[,]
{
{ "Test organization", false }
});
After that you should be able to manage the creation of the new foreign key field, giving 1 as default value.

ForeignKey to the same table with custom column name

I have a model User :
public class User
{
[Key]
public int IDUser { get; set; }
[Required]
public string Forename { get; set; }
[Required]
public string Name { get; set; }
public int? IDUser_CreatedBy { get; set; }
public User User_CreatedBy { get; set; }
}
User can have its creator (User_CreatedBy) with its ID (IDUser_CreatedBy) which resides in the same table of course but I want to have an opportunity to leave it as null value (User with unknown creator). That's why IDUser_CreatedBy has int? nullable type.
I don't know how to set up my fluent API in order to bind that foreign key IDUser_CreatedBy to primary key IDUser in the same table.
I know that if I delete IDUser_CreatedBy foreign key from that model and add new migration then EF core will make for me shadow property foreign key implicitly but I want to have an opportunity to update my User later (in MVC controller) with custom created column IDUser_CreatedBy and be able to name that column for myself. Besides I don't want that shadow property since I don't have any control over naming that column.
How can I achieve that ?
EDIT
#IvanStoev - thank you for your answer but your example doesn't produce for me a valid migration code :
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Users_Users_CreatedByIDUser",
table: "Users");
migrationBuilder.RenameColumn(
name: "CreatedByIDUser",
table: "Users",
newName: "UserIDUser");
migrationBuilder.RenameIndex(
name: "IX_Users_CreatedByIDUser",
table: "Users",
newName: "IX_Users_UserIDUser");
migrationBuilder.AddColumn<int>(
name: "IDUser_CreatedBy",
table: "Users",
nullable: true);
migrationBuilder.CreateIndex(
name: "IX_Users_IDUser_CreatedBy",
table: "Users",
column: "IDUser_CreatedBy");
migrationBuilder.AddForeignKey(
name: "FK_Users_Users_IDUser_CreatedBy",
table: "Users",
column: "IDUser_CreatedBy",
principalTable: "Users",
principalColumn: "IDUser",
onDelete: ReferentialAction.Restrict);
migrationBuilder.AddForeignKey(
name: "FK_Users_Users_UserIDUser",
table: "Users",
column: "UserIDUser",
principalTable: "Users",
principalColumn: "IDUser",
onDelete: ReferentialAction.Restrict);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Users_Users_IDUser_CreatedBy",
table: "Users");
migrationBuilder.DropForeignKey(
name: "FK_Users_Users_UserIDUser",
table: "Users");
migrationBuilder.DropIndex(
name: "IX_Users_IDUser_CreatedBy",
table: "Users");
migrationBuilder.DropColumn(
name: "IDUser_CreatedBy",
table: "Users");
migrationBuilder.RenameColumn(
name: "UserIDUser",
table: "Users",
newName: "CreatedByIDUser");
migrationBuilder.RenameIndex(
name: "IX_Users_UserIDUser",
table: "Users",
newName: "IX_Users_CreatedByIDUser");
migrationBuilder.AddForeignKey(
name: "FK_Users_Users_CreatedByIDUser",
table: "Users",
column: "CreatedByIDUser",
principalTable: "Users",
principalColumn: "IDUser",
onDelete: ReferentialAction.Restrict);
}
It does produces a ForeignKey column that I wanted (IDUser_CreatedBy) and a valid index for that key column (IX_Users_IDUser_CreatedBy) but it also adds another ForeignKey (UserIDUser) witch is a shadow property I guess. So as a result I have 2 different ForeignKey columns that refer to one Primerykey column (IDUser) in the same table. In my case migration in fact renames old column (CreatedByIDUser) to new one (UserIDUser) which is a remnant of my previous shadow property ForeignKey column. What I'm looking for is that migration will get rid completely of that previous shadow property and introduse only one, new ForeignKey column (IDUser_CreatedBy). Any suggestions ?
EDIT 2
#viveknuna - thank you for your example but it also doesn't do the job for me.
Migration looks like this :
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Users_Users_CreatedByIDUser",
table: "Users");
migrationBuilder.RenameColumn(
name: "CreatedByIDUser",
table: "Users",
newName: "User_CreatedByIDUser");
migrationBuilder.RenameIndex(
name: "IX_Users_CreatedByIDUser",
table: "Users",
newName: "IX_Users_User_CreatedByIDUser");
migrationBuilder.AddColumn<int>(
name: "IDUser_CreatedBy",
table: "Users",
nullable: true);
migrationBuilder.AddForeignKey(
name: "FK_Users_Users_User_CreatedByIDUser",
table: "Users",
column: "User_CreatedByIDUser",
principalTable: "Users",
principalColumn: "IDUser",
onDelete: ReferentialAction.Restrict);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Users_Users_User_CreatedByIDUser",
table: "Users");
migrationBuilder.DropColumn(
name: "IDUser_CreatedBy",
table: "Users");
migrationBuilder.RenameColumn(
name: "User_CreatedByIDUser",
table: "Users",
newName: "CreatedByIDUser");
migrationBuilder.RenameIndex(
name: "IX_Users_User_CreatedByIDUser",
table: "Users",
newName: "IX_Users_CreatedByIDUser");
migrationBuilder.AddForeignKey(
name: "FK_Users_Users_CreatedByIDUser",
table: "Users",
column: "CreatedByIDUser",
principalTable: "Users",
principalColumn: "IDUser",
onDelete: ReferentialAction.Restrict);
}
It renames my remnant shadow property ForeignKey a new name but it keeps that shadow property. Migration also adds new column IDUser_CreatedBy which is not a ForeignKey (there's no AddForeignKey and CreateIndex method for that column).
EDIT 3
#Ivan Stoev - you're right. I haven't submitted whole model because I thought it will have no impact on the result but now it's clear it has ... :) First of all - I indeed created a brand new command line project and managed to scaffold the correct migration as you said. Then I realised that my model has another property which is public List<User> UsersAdded { get; set; } which depicts all users that were added by that particular User. And that is the culprit. It adds new column UserIDUser to newly created migration. So the final question is : how can I achieve all that what I need with that new property public List<User> UsersAdded { get; set; } ? because I want to have an opportunity to include User collecion that this User created while getting a User in my MVC controller. As a formality I submit my whole model (correctly this time) :
public class User
{
[Key]
public int IDUser { get; set; }
[Required]
public string Forename { get; set; }
[Required]
public string Name { get; set; }
public string AvatarPath { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public string Password { get; set; }
public bool IsWebUser { get; set; }
public DateTimeOffset CreatedAt { get; set; }
public int? IDUser_CreatedBy { get; set; }
public User User_CreatedBy { get; set; }
public List<User> UsersAdded { get; set; }
}
EF Core fluent API gives you a full control over naming the table columns, regardless of whether you use explicit or shadow model property. The unconventional foreign key property is mapped with HasForeignKey fluent API of the relationship configuration.
Your entity model falls into Single Navigation Property with explicit FK property category, which can be mapped like this:
modelBuilder.Entity<User>()
.HasOne(e => e.User_CreatedBy) // reference navigation property
.WithMany() // no collection navigation property
.HasForeignKey(e => e.IDUser_CreatedBy); // foreign key property

Categories