0

I am trying to update a 1-N relationship using Entity Framework.

I have two tables:

Story   <-- 1 ----- N -->  StoryLocation

I figured that if i want to update the N part of the relation (for a given Story) most efficiently ,i would delete all the N entities and then i would "reattach" them.

So I do the following:

[HttpPost]
[Route("ad/story-location/attach")]
public async Task<HttpResponseMessage>Reattach([FromQuery]long storyid,[FromBody]StoryLocation[] data)
{
            try
            {
                var delRecords = from record in this._context.StoryLocation
                          where record.StoryId == data[0].StoryId
                          select record;
                this._context.RemoveRange(delRecords);
                await this._context.StoryLocation.AddRangeAsync(data);
                int rowsAffected = await this._context.SaveChangesAsync();

                return new HttpResponseMessage
                {
                    StatusCode = System.Net.HttpStatusCode.OK,
                    Content = new StringContent($"Rows affected:{rowsAffected.ToString()}")
                };
            }
            catch (Exception ex)
            {
                return new HttpResponseMessage
                {
                    StatusCode = System.Net.HttpStatusCode.NoContent,
                    Content = ex.ToHttpContent()
                };
            }
}

And I get the following exception:

The instance of entity type 'StoryLocation' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Bercovici Adrian
  • 8,794
  • 17
  • 73
  • 152

1 Answers1

1
    [HttpPost]
    [Route("ad/story-location/attach")]
    public async Task<HttpResponseMessage>Reattach([FromQuery]long storyid,[FromBody]StoryLocation[] data)
    {
        try
        {
            var delRecords = from record in this._context.StoryLocation
                      where record.StoryId == data[0].StoryId
                      select record;
            this._context.RemoveRange(delRecords);
            foreach(var item in delRecords)
            {
                 if (!item .IsNull()) // I'm using a extension method
                 {
                     // detach
                     _context.Entry(item ).State = EntityState.Detached;
                 }
            }
            await this._context.StoryLocation.AddRangeAsync(data);
            int rowsAffected=await this._context.SaveChangesAsync();
            return new HttpResponseMessage
            {
                StatusCode = System.Net.HttpStatusCode.OK,
                Content = new StringContent($"Rows affected:{rowsAffected.ToString()}")
            };
        }
        catch (Exception ex)
        {

            return new HttpResponseMessage
            {
                StatusCode = System.Net.HttpStatusCode.NoContent,
                Content = ex.ToHttpContent()
            };
        }
    }
sebu
  • 2,824
  • 1
  • 30
  • 45