According to other questions (here and here) it's possible to catch unique key violations in Entity Framework 6 by catching the thrown exception and inspecting it's InnerException
.
When calling DbContext.SaveChanges()
with a duplicate set of data, an exception is thrown but it is a fairly standard InvalidOperationException
, and it's InnerException
is null
.
How can I detect duplicate key violations in Entity Framework Core?
Update with more context (pun intended)
The specific violation I'm trying to catch/detect is when adding a link between two entities (Team and User) that are joined by a many-to-many relationship.
System.InvalidOperationException: The instance of entity type 'TeamUser' cannot be tracked because another instance of this type with the same key is already being tracked. When adding new entities, for most key types a unique temporary key value will be created if no key is set (i.e. if the key property is assigned the default value for its type). If you are explicitly setting key values for new entities, ensure they do not collide with existing entities or temporary values generated for other new entities. When attaching existing entities, ensure that only one entity instance with a given key value is attached to the context.
User entity class:
public class User
{
[Key]
public string Name { get; set; }
public ICollection<TeamUser> TeamUsers { get; set; }
}
Team entity class:
public class Team
{
[Key]
public string Id { get; set; }
[Required]
public string Name { get; set; }
public ICollection<Template> Templates { get; set; }
public ICollection<Checklist> Checklists { get; set; }
public ICollection<TeamUser> TeamUsers { get; set; }
}
TeamUser entity class:
public class TeamUser
{
public string TeamId { get; set; }
public Team Team { get; set; }
public string UserName { get; set; }
public User User { get; set; }
}
My DbContext
subclass configures the many-to-many relationship between Teams and Users:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var teamUserEntity = modelBuilder.Entity<TeamUser>();
teamUserEntity
.HasKey(tu => new { tu.TeamId, tu.UserName });
teamUserEntity
.HasOne(tu => tu.Team)
.WithMany(t => t.TeamUsers)
.HasForeignKey(tu => tu.TeamId);
teamUserEntity
.HasOne(tu => tu.User)
.WithMany(u => u.TeamUsers)
.HasForeignKey(tu => tu.UserName);
}
EF Core has generated the TeamUser
table as follows:
CREATE TABLE "TeamUser" (
"TeamId" TEXT NOT NULL,
"UserName" TEXT NOT NULL,
CONSTRAINT "PK_TeamUser" PRIMARY KEY ("TeamId", "UserName"),
CONSTRAINT "FK_TeamUser_Teams_TeamId" FOREIGN KEY ("TeamId") REFERENCES "Teams" ("Id") ON DELETE CASCADE,
CONSTRAINT "FK_TeamUser_Users_UserName" FOREIGN KEY ("UserName") REFERENCES "Users" ("Name") ON DELETE CASCADE
);
CREATE INDEX "IX_TeamUser_UserName" ON "TeamUser" ("UserName");