0

In the following code, I receive an error in _context.SaveChanges(); when adding a new record to FeedbackComments inside the first foreach loop. The error is New transaction is not allowed because there are other threads running in the session.. Any ideas why this is happening?

BTW, I keep receiving the same error when SaveChanges is called only once after the outer loop.

List<FeedbackComment> feedbackComments = comments.Select(c => new FeedbackComment
{
    Id = c.Id,
    CommentText = c.Content,
    SubmissionId = submissionId,
    UserDisplayName = c.Author.DisplayName,
    DateCreated = c.CreatedTime.GetValueOrDefault(),
    FeedbackReplies = c.Replies.Select(r => new FeedbackReply
    {
        Id = r.Id,
        UserDisplayName = r.Author.DisplayName,
        ReplyText = r.Content,
        DateCreated = r.CreatedTime.GetValueOrDefault(),
        FeedbackCommentId = c.Id
    }).ToList()
}).ToList();

_context.SaveChanges();


foreach (FeedbackComment c in feedbackComments)
{
    if (!_context.FeedbackComments.Any(fc => fc.Id == c.Id))
    {
        ApplicationUser commentOwner = _context.ApplicationUsers.FirstOrDefault(au => au.GoogleDisplayName == c.UserDisplayName);

        if(commentOwner != null)
        {
            c.UserId = commentOwner.Id;

            _context.FeedbackComments.Add(c);
            newComments = true;
            _context.SaveChanges();

        }

    }


    foreach (FeedbackReply r in c.FeedbackReplies)
    {
        if (!_context.FeedbackReplies.Any(fr => fr.Id == r.Id))
        {
            ApplicationUser replyOwner = _context.ApplicationUsers.FirstOrDefault(au => au.GoogleDisplayName == c.UserDisplayName);

            if (replyOwner != null)
            {
                r.UserId = replyOwner.Id;

                _context.FeedbackReplies.Add(r);
                newComments = true;
                _context.SaveChanges();

            }
        }

    }
}
renakre
  • 8,001
  • 5
  • 46
  • 99
  • Related: https://stackoverflow.com/a/2180920/261050 – Maarten May 13 '20 at 13:25
  • 1
    Indeed; do a single `_context.SaveChanges();` outside the `foreach(var ... in feedbackComments)`. You cannot save data while iterating over the result of a query. – Maarten May 13 '20 at 13:27

2 Answers2

0

When you are trying to save a change using a transaction, you should wait until any other transactions are completed. On the other hand, waiting for the previous transaction to be completed, makes severe performance issue. You should put _context.SaveChanges(); outside the foreach loop like this:

foreach (FeedbackReply r in c.FeedbackReplies)
{
    if (!_context.FeedbackReplies.Any(fr => fr.Id == r.Id))
    {
        ApplicationUser replyOwner = _context.ApplicationUsers.FirstOrDefault(au => au.GoogleDisplayName == c.UserDisplayName);

        if (replyOwner != null)
        {
            r.UserId = replyOwner.Id;
            _context.FeedbackReplies.Add(r);
            newComments = true;
        }
    }
}
_context.SaveChanges();

In the above code, all changes are applied to the database in one transaction.

Hadi Samadzad
  • 1,480
  • 2
  • 13
  • 22
0

Why are you calling SaveChanges after the initial data fetch? If you leave that one out and call SaveChanges only once, at the end, it should work, as Hadi said.

Gamingdevil
  • 355
  • 1
  • 12