I currently have 2 classes that are mapped to each other. I am receiving the following error:
The MERGE statement conflicted with the FOREIGN KEY constraint "FK_Stories_Users_UserId". The conflict occurred in database "StoriesDb", table "dbo.Users", column 'Id'.
I am trying to add the UserId FK to the new Story entity I just created. My classes look something like this (snipped irrelevant properties)
public class Story : ITimestamp
{
public Story() {}
public int Id { get; set; }
public string Description { get; set; }
public string DescriptionMarkdown { get; set; }
public string Title { get; set; }
public Guid UserId { get; set; }
public virtual User User { get; set; }
public virtual DateTime CreatedDate { get; set; }
public virtual DateTime ModifiedDate { get; set; }
}
public class User : ITimestamp
{
public Guid Id { get; set; }
public string Username { get; set; }
public string Email { get; set; }
public string PasswordHash { get; set; }
public string PasswordSalt { get; set; }
public virtual IList<Comment> Comments { get; set; } = new List<Comment>();
public virtual DateTime CreatedDate { get; set; }
public virtual DateTime ModifiedDate { get; set; }
}
I add the new story like this:
public async Task<StorySummaryViewModel> Create(CreateViewModel model, string username, Guid userId)
{
var story = await StoriesDbContext.Stories.AddAsync(new Story() {
Title = model.Title,
DescriptionMarkdown = model.DescriptionMarkdown,
Description = CommonMarkConverter.Convert(model.DescriptionMarkdown),
UserId = userId
});
var rowCount = await StoriesDbContext.SaveChangesAsync();
[...]
}
Through some of the other Create methods, I know that adding a new entity object to a second new entity's navigation property will save correctly. However, at this point I do not want to be able to modify the User entity when saving a Story entity, which is why I set the UserId property (marked as FK). But it doesn't seem to be working.
I have also compared the UserId passed to the method against the database data and they are both the same value.
The technique of only setting the FK Id property is something I use in EF6 and it works as expected.
Am I missing something in my DbContext or in my mappings that would allow me to SaveChanges the new entity by foreign key id?
This question is very similar to this StackOverflow question. But unfortunately it only deals with newly created entities.
Edit I am including the mapping I have for both story and user.
public class StoryMap : IEntityTypeConfiguration<Story>
{
public void Map(EntityTypeBuilder<Story> builder)
{
builder.HasKey(e => e.Id);
builder.Property(s => s.Url).IsRequired();
builder.Property(s => s.Title).IsRequired();
builder.HasOne(e => e.User).WithMany().HasForeignKey(e => e.UserId);
builder.HasMany(e => e.Comments).WithOne(c => c.Story).HasForeignKey(c => c.StoryId);
builder.HasMany(e => e.Votes).WithOne(v => v.Story).HasForeignKey(v => v.StoryId);
}
}
public class UserMap : IEntityTypeConfiguration<User>
{
public void Map(EntityTypeBuilder<User> builder)
{
builder.HasKey(u => u.Id);
builder.HasIndex(u => u.Email);
builder.Property(u => u.PasswordHash).IsRequired();
builder.Property(u => u.PasswordSalt).IsRequired();
builder.Property(u => u.Username).IsRequired();
builder.Property(u => u.Email).IsRequired();
// Navigation
[..snip..]
builder.HasMany(u => u.Stories).WithOne(c => c.User).HasForeignKey(s => s.UserId);
}
}
Edit for migration
migrationBuilder.CreateTable(
name: "Stories",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
CreatedDate = table.Column<DateTime>(nullable: false),
Description = table.Column<string>(nullable: true),
DescriptionMarkdown = table.Column<string>(nullable: true),
ModifiedDate = table.Column<DateTime>(nullable: false),
Title = table.Column<string>(nullable: false),
Url = table.Column<string>(nullable: false),
UserId = table.Column<Guid>(nullable: false),
UserIsAuthor = table.Column<bool>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Stories", x => x.Id);
table.ForeignKey(
name: "FK_Stories_Users_UserId",
column: x => x.UserId,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});