Не знаю, как справиться с конфликтами параллелизма. EF Core - PullRequest
0 голосов
/ 17 марта 2020

Проблема, с которой я сталкиваюсь, заключается в том, что когда пользователь нажимает на рейтинг в первый раз, он выдает мне ошибку:

Не знаю, как обрабатывать конфликты параллелизма для NoSleepers.Core.Rating

в NoSleepers.Data.StoryRepository.WriteRatingForStory (Int32 storyId, Int32 userId, Int32 Score) в C: \ Users \ dough \ Desktop \ Разработка веб-сайтов \ Nosleepers \ Site \ NoSleepers.Data \ StoryRepository.cs: строка 91 в NoSleepers.Controllers.RatingsController.WriteRating (рейтинг Int32 storyId, Int32) в C: \ Users \ dough \ Desktop \ Разработка сайтов \ Nosleepers \ Site \ NoSleepers \ Controllers \ RatingsController.cs: строка 29 в Microsoft.AspNetCore. Mvc .Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute (преобразователь IActionResultTypeMapper, аргумент ObjectMethodExecutor, объектный контроллер, аргументы Object []) в Microsoft.AspNetCore. * 10ctionAgna. , ValueTask`1 actionResultValueTask) в Microsoft.Asp NetCore. Mvc .Infrastructure.ControllerActionInvoker.g__Awaited | 10_0 (вызывающий ControllerActionInvoker, задача lastTask, следующее состояние, область действия области, состояние объекта, логическое значение isCompleted) в Microsoft.AspNetCore. Mvc .Infrastructure.ControllerArowInteced.Exception.Context.ContextSuneInteSec. в Microsoft.AspNetCore. Mvc .Infrastructure.ControllerActionInvoker.Next (State & next, Scope & scope, Object & state, Boolean & isCompleted) в Microsoft.AspNetCore. Mvc .Infrastructure.ControllerActionInvoker.g__Awaited | 13_0 invakAler (для управления вызовом) Состояние следующее, область действия, состояние объекта, логическое значение isCompleted) в Microsoft.AspNetCore. Mvc .Infrastructure.ResourceInvoker.g__Awaited | 24_0 (вызов ресурса ResourceInvoker, задача lastTask, следующее состояние, область действия области, состояние объекта, логическое значение isCompleted) в корпорации Майкрософт. AspNetCore. Mvc .Infrastructure.ResourceInvoker.Rethrow (контекст ResourceExecutedContextSealed) в Microsoft.AspNetCore. Mvc .Infrastructure.ResourceInvoker.Next (состояние и следующее, область действия & scope, Object & state, Boolean & isCompleted) в Microsoft.AspNetCore. Mvc .Infrastructure.ResourceInvoker.g__Awaited | 19_0 (вызов ресурса ResourceInvoker, Task lastTask, следующее состояние, область действия Scope, состояние объекта, логическое значение isCompleted) в Microsoft.AspNetCore. Mvc .Infrastructure.ResourceInvoker.g__Awaited | 17_0 (ResourceInvoker invoker, задача Task, IDisposable scope) в Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask | 6_0 (конечная точка, конечная точка запроса, учетная запись обратного вызова. Invoke (контекст HttpContext) в Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke (контекст HttpContext) в Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke (контекст HttpContext)

* 1008 Ранее добавлен рейтинг для пользователя в базе данных вручную. Я не могу понять, что я делаю неправильно. Буду признателен за любую помощь.

EntityConfig и методы

public void Configure(EntityTypeBuilder<Story> builder)
{
    builder.ToTable("Stories");
    builder.HasKey(x => x.Id);

    builder.HasOne(s => s.Author)
           .WithMany(a => a.Stories)
           .HasForeignKey(s => s.AuthorId);

    builder.OwnsMany(x => x.Ratings, x =>
    {
        x.WithOwner().HasForeignKey(x => x.StoryId);
        x.Property(x => x.Score);
        x.HasKey(y => new { y.StoryId, y.UserId });
        x.ToTable("Ratings");

    });
    builder.OwnsMany(x => x.Favorites, x =>
    {
        x.WithOwner().HasForeignKey(x => x.StoryId);
        x.HasKey(y => new { y.StoryId, y.UserId });
        x.ToTable("Favorites");
    });
}

public void WriteRating(int userId, double newRating)
    {
        if (HasUserWrittenRating(userId))
        {
            Ratings.FirstOrDefault(c => c.UserId == userId && c.StoryId == this.Id).Score = newRating;
            AverageRating = Ratings.Average(r => r.Score);
        }
        else
        {
            Ratings.Add(new Rating() { StoryId = this.Id, Score = newRating, UserId = userId });
            AverageRating = ((AverageRating * NumberOfRatings - 1) + newRating) / NumberOfRatings;
        }
    }

private bool HasUserWrittenRating(int userId)
    {
        return Ratings.Any(rat => rat.UserId == userId);
    }

public async Task WriteRatingForStory(int storyId, int userId, int score)
    {
    // Get the story that was rated
    var story = await _dbContext.Stories.FirstOrDefaultAsync(story => story.Id == storyId);

    // Updating thestory with the new rating
    story.WriteRating(userId, score);

    //_dbContext.Stories.Update(story);

    // Save the updated story to the database
    var saved = false;
    while (!saved)
    {
        try
        {
            // Attempt to save changes to the database
            _dbContext.SaveChanges();
            saved = true;
        }
        catch (DbUpdateConcurrencyException ex)
        {
            foreach (var entry in ex.Entries)
            {
                if (entry.Entity is Story)
                {
                    var proposedValues = entry.CurrentValues;
                    var databaseValues = entry.GetDatabaseValues();

                    foreach (var property in proposedValues.Properties)
                    {
                        var proposedValue = proposedValues[property];
                        var databaseValue = databaseValues[property];

                        // TODO: decide which value should be written to database
                        // proposedValues[property] = <value to be saved>;
                    }

                    // Refresh original values to bypass next concurrency check
                    entry.OriginalValues.SetValues(databaseValues);
                }
                else
                {
                    throw new NotSupportedException(
                        "Don't know how to handle concurrency conflicts for "
                        + entry.Metadata.Name);
                }
            }
        }
    }
}

Рейтинговая структура базы данных (UserId, StoryId являются первичными, счет в виде числа с плавающей запятой)

Истории БД структура (Id как Primary, AuthorId, название, дата, оценка, средняя оценка, URL)

...