MVC Delete record with multiple required foreign key constraints
Removing from a join-payload table in MVC isn't fun at all. Similar questions are about a single foreign key and my situation is unique enough that I guaranteed it a question for myself (if not, point me to the link)
I have this model (which acts as my joint payload table - it acts as the connection table between ApplicationUser and Car, which are both data models)
public class UserHasCar
{
// Foreign keys
[Key, Column(Order = 0)]
public string ApplicationUserId { get; set; }
[Key, Column(Order = 1)]
public int CarId { get; set; }
// Navigation properties
[Required]
public virtual ApplicationUser ApplicationUser { get; set; }
[Required]
public virtual Car Car { get; set; }
// Additional fields
public int YearsDriven { get; set; }
}
public class Car
{
public int ID { get; set; }
public virtual ICollection<UserHasCar> UserHasCars { get; set; }
}
public class ApplicationUser : IdentityUser
{
public virtual ICollection<UserHasCar> UserHasCars { get; set; }
}
The problem occurs when I try to delete the entry (delete the UserHasCar object from the database). Since UserHasCar has two foreign keys, after running this code, I get the following error:
List<UserHasCar> list = (from t in context.UserHasCars where t.ApplicationUserId == userId select t).ToList();
foreach (UserHasCar car in list)
{
context.UserHasCar.Remove(car); // BOOM!
}
Disgusting error: A referential integrity constraint violation occurred: A primary key property that is a part of referential integrity constraint cannot be changed when the dependent object is Unchanged unless it is being set to the association principal object. The principal object must be tracked and not marked for deletion.
My table definition looks like this:
CREATE TABLE [dbo].[UserHasCars] (
[ApplicationUserId] NVARCHAR (128) NOT NULL,
[CarId] INT NOT NULL,
[YearsDriven] INT NOT NULL,
CONSTRAINT [PK_dbo.UserHasCars] PRIMARY KEY CLUSTERED ([ApplicationUserId] ASC, [CarId] ASC),
CONSTRAINT [FK_dbo.UserHasCars_dbo.AspNetUsers_ApplicationUserId] FOREIGN KEY ([ApplicationUserId]) REFERENCES [dbo].[AspNetUsers] ([Id]) ON DELETE CASCADE,
CONSTRAINT [FK_dbo.UserHasCars_dbo.Cars_CarId] FOREIGN KEY ([CarId]) REFERENCES [dbo].[Cars] ([ID]) ON DELETE CASCADE
);
Do I need to do something as simple as EntityState.Deleted / Modified for my two foreign keys? I know he is complaining about my clustered primary key and how I cannot delete it without deleting my foreign key references ... I'm sure I'm missing something small here.
EDIT
As I will go into more detail, this line List<UserHasCar> list = (from t in context.UserHasCars where t.ApplicationUserId == userId select t).ToList();
does not pull in the desired ApplicationUser or Car from my database table, all values ββare zero. I can see the request is not pulling into the proper ApplicationUser or Car, but why?
source to share
The problem was that the Car and User IDs were set to their default values ββand did not display the actual rows in the table. I wrote about how I solved it on this page (at the bottom):
http://programmerscheatbook.blogspot.com/2014/08/mvc-making-join-table-with-payload.html
ApplicationDbContext db = new ApplicationDbContext();
string userId = [USER ID];
int carId = [CAR ID];
List <UserHasCar> list = (from rec in db.UserHasCars
join car in db.Cars on rec.CarId equals car.Id
where rec.ApplicationUserId == userId && rec.CarId == carId
select rec).ToList();
foreach (UserHasCar car in list)
{
db.UserHasCars.Remove(car);
}
db.SaveChanges();
source to share
You might be able to change the delete / cascading rules in the database regarding key dependencies. SQL ON DELETE CASCADE, which path is the deletion on?
Be sure to read first, and remember exactly what you are doing:
source to share
public ActionResult DeleteConfirmed(long id)
{
EmployeeContacts employeecontect = db.EmployeeContacts.Find(id);
if(employeecontect!=null)
{
db.EmployeeContacts.Remove(employeecontect);
db.SaveChanges();
}
Employee employee = db.Employee.Find(id);
db.Employee.Remove(employee);
db.SaveChanges();
return RedirectToAction("Index");
}
source to share