1

I have an error: Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: 'The database operation was expected to affect 1 row(s), but actually affected 0 row(s); data may have been modified or deleted since entities were loaded.

when I am trying to add a comment to a post in database using Entity Framework and save changes. I don't know why. What am I doing wrong?

Here I have the error:

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    private readonly ApplicationDbContext _applicationDbContext;
    public ValuesController(ApplicationDbContext applicationDbContext)
    {
        _applicationDbContext = applicationDbContext;
    }

    [HttpGet]
    public IActionResult Get()
    {
        var post = _applicationDbContext.Posts.First();
        post.AddComment(Guid.NewGuid(), "aaa", "bbb");
        _applicationDbContext.SaveChanges(); // here error

        return Ok();
    }
}

Entity Framework configuration - probably something is wrong here?:

public class PostConfiguration : IEntityTypeConfiguration<Post>
{
    public void Configure(EntityTypeBuilder<Post> builder)
    {
        builder.ToTable("Posts");
        builder.HasKey(x => x.PostId);

        builder.HasMany(x => x.Comments).WithOne().HasForeignKey("PostId");
    }
}

public class CommentConfiguration : IEntityTypeConfiguration<Comment>
{
    public void Configure(EntityTypeBuilder<Comment> builder)
    {
        builder.ToTable("Comments");
        builder.HasKey(x => x.CommentId);

        builder.Property(x => x.CommentStatus)
            .HasColumnName("CommentStatusId")
            .HasConversion(new EnumToNumberConverter<CommentStatus, int>());
    }
}

public class ApplicationDbContext : DbContext
{
    public DbSet<Post> Posts { get; set; }
    public DbSet<Comment> Comments { get; set; }


    public ApplicationDbContext(
        DbContextOptions options) : base(options)
    {
    }


    public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
    {
        var result = await base.SaveChangesAsync(cancellationToken);

        return result;
    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());

        base.OnModelCreating(builder);
    }
}

Here is my Post class:

public class Post
{
    public Guid PostId { get; private set; }

    public string Title { get; private set; }

    public string Content { get; private set; }               
    
    public List<Comment> Comments { get; private set; } = new List<Comment>();


    public Post(Guid postId, string title, string content)
    {
        PostId = postId;
        Title = title;
        Content = content;
    }


    public void AddComment(Guid commentId, string author, string content)
    {
        var comment = new Comment(commentId, author, content);
        Comments.Add(comment);
    }
}

Here is my Comment class:

public class Comment
{
    public Guid CommentId { get; private set; }

    public string Author { get; private set; }

    public string Content { get; private set; }

    public CommentStatus CommentStatus { get; private set; }


    public Comment(Guid commentId, string author, string content)
    {
        CommentId = commentId;
        Author = author;
        Content = content;
        CommentStatus = CommentStatus.New;
    }
}   

Here is my CommentStatus class:

public enum CommentStatus
{
    New = 1,
    Accepted = 2,
    Rejected = 3
}

In Program.cs I have:

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connectionString));
Yunnosch
  • 26,130
  • 9
  • 42
  • 54
MrChudz
  • 909
  • 3
  • 10
  • 17
  • OK, I know, I have to add: builder.Property(x => x.Postd).ValueGeneratedNever(); builder.Property(x => x.CommentId).ValueGeneratedNever(); – MrChudz Feb 17 '22 at 07:08
  • 1
    Please do not edit solution announcements into the question. Accept (i.e. click the "tick" next to it) one of the existing answer, if there are any. You can also create your own answer, and even accept it, if your solution is not yet covered by an existing answer. Compare https://stackoverflow.com/help/self-answer – Yunnosch Feb 17 '22 at 07:11
  • https://stackoverflow.com/questions/39460686/unable-to-edit-db-entries-using-efcore-entitystate-modified-database-operatio – THEoneANDonly Feb 17 '22 at 15:57

1 Answers1

1

OK, I know, I have to add:

builder.Property(x => x.Postd).ValueGeneratedNever(); 
builder.Property(x => x.CommentId).ValueGeneratedNever();
MrChudz
  • 909
  • 3
  • 10
  • 17