Code: Select all
internal sealed class AddCommentHandler(
IPostsDbContext dbContext,
ILogger logger
) : IRequestHandler
{
public async Task Handle(AddCommentCommand request, CancellationToken cancellationToken)
{
Post? post = await dbContext.Posts.FindAsync([request.PostId], cancellationToken);
post.AddComment(
request.AuthorId,
request.Content,
request.ParentCommentId
);
await dbContext.SaveChangesAsync(cancellationToken);
logger.LogDebug("Successfully added comment to post {@PostId}", request.PostId);
}
}
< /code>
When calling SaveChangesAsync
Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: 'The database operation was expected to affect 1 row(s), but actually affected 0 row(s); Die Daten wurden möglicherweise geändert oder gelöscht, seit Entitäten geladen wurden. In https://go.microsoft.com/fwlink/?linkid=527962 finden Sie Informationen zum Verständnis und zur Verständnis optimistischer Parallelitätsausnahmen.
Code: Select all
Post
Code: Select all
public sealed class Post : EntityHasDomainEvents, IAuditableEntity
{
public Guid Id { get; }
public Guid AuthorId { get; private set; }
public string Content { get; private set; }
public DateTime CreatedAtUtc { get; set; }
public DateTime UpdatedAtUtc { get; set; }
private readonly List _comments = [];
public IReadOnlyCollection Comments => _comments;
public Author Author { get; private set; }
private Post() { }
public Post(Guid authorId, string content)
{
Id = Guid.NewGuid();
AuthorId = authorId;
Content = content;
Raise(new PostCreatedDomainEvent(Id));
}
public void AddComment(Guid authorId, string content, Guid? parentCommentId)
{
var comment = new Comment(Id, authorId, content, parentCommentId);
_comments.Add(comment);
}
}
< /code>
Comment
Code: Select all
public sealed class Comment : IAuditableEntity
{
public Guid Id { get; }
public Guid PostId { get; private set; }
public Guid AuthorId { get; private set; }
public string Content { get; private set; }
public Guid? ParentCommentId { get; private set; }
public DateTime CreatedAtUtc { get; set; }
public DateTime UpdatedAtUtc { get; set; }
public Author Author { get; private set; }
public Post Post { get; private set; }
private Comment() { }
public Comment(Guid postId, Guid authorId, string content, Guid? parentCommentId = null)
{
Id = Guid.NewGuid();
PostId = postId;
AuthorId = authorId;
Content = content;
ParentCommentId = parentCommentId;
}
}
< /code>
Entity config:
internal sealed class PostConfiguration : IEntityTypeConfiguration
{
public void Configure(EntityTypeBuilder builder)
{
builder.HasKey(p => p.Id);
builder.Property(p => p.Content)
.HasMaxLength(515);
builder.HasMany(p => p.Comments)
.WithOne(c => c.Post)
.HasForeignKey(c => c.PostId)
.OnDelete(DeleteBehavior.Cascade);
}
}
internal sealed class CommentConfiguration : IEntityTypeConfiguration
{
public void Configure(EntityTypeBuilder builder)
{
builder.HasKey(c => c.Id);
builder.Property(c => c.Content)
.IsRequired()
.HasMaxLength(500);
builder.HasOne(c => c.Post)
.WithMany(p => p.Comments)
.HasForeignKey(c => c.PostId)
.OnDelete(DeleteBehavior.Cascade);
builder.HasIndex(c => c.PostId);
builder.HasIndex(c => c.ParentCommentId);
}
}