Search code examples
automapperentity-framework-coreput

Entity Framework Core 2 : Easily update an object and it's relations


In an asp net core + ef core 2.0 web api project I'm using a put method defined as below in which I have to update each properties of my entities one by one :

public async Task<IActionResult> PutCIApplication([FromRoute] Guid id, [FromBody] CIApplication cIApplication)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        if (id != cIApplication.ID)
        {
            return BadRequest();
        }

        string userLang = HttpContext.Request.Headers["UserCulture"].ToString();
        var dbCIApplication = await _context.CIApplications.Include(c => c.Translations).Include(c => c.DeploymentScenarios).SingleOrDefaultAsync(m => m.ID == id);

        if (dbCIApplication == null)
        {
            return NotFound();
        }

        //Name and Desc are localized properties, they are stored in a collection of Translation with one to many relationship
        dbCIApplication.Translations[userLang].Name = cIApplication.Name;
        dbCIApplication.Translations[userLang].Description = cIApplication.Description;
        dbCIApplication.UpdatedBy = cIApplication.UpdatedBy;
        dbCIApplication.Status = cIApplication.Status;
        dbCIApplication.Publisher = cIApplication.Publisher;
        // And the list goes on...
        //... and on...

        _context.CIApplications.Update(dbCIApplication);

        try
        {
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!CIApplicationExists(id))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }

        return NoContent();
    }

It works very well, so I don't really have an issue but I was wondering if there a way to avoid the part where I copy each properties one by one.

I tried with automapper but as it creates a new instance I get a "cannot be tracked because another instance of this type with the same key is already being tracked" error.

I would have liked to use some reusable code in which I could pass my object to update and a list of proprties to ignore. But I'm not enough a good coder to set it up, if someone had a great idea it would be awesome !

Thanks !


Solution

  • This is the point where you should probably start rethinking your design but nevertheless you can in fact us AutoMapper and turn off tracking.

    Check out this link: https://learn.microsoft.com/en-us/ef/core/querying/tracking

    var dbCIApplication = await _context
                    .CIApplications
                    .AsNoTracking()
                    .Include(c => c.Translations)
                    .Include(c => c.DeploymentScenarios)
                    .SingleOrDefaultAsync(m => m.ID == id);