Entity Framework Core not filling object by foreign key on update

c# entity-framework-core

Question

I see this error when updating an Application. The object has two external connections: ApplicationVisitors and ApplicationPlatforms. The properties in Application have been updated, but external connections was not be updated. What am I doing wrong? How to update Application correctly?

Route

[Route("update")]
[HttpPut]
public async Task<IActionResult> UpdateApplication(ApplicationDTO applicationDTO)
{
     if (!ModelState.IsValid)
         return BadRequest("Модель не валидна!");

     await applicationService.UpdateApplication(applicationDTO);
     return Ok();
}

Service

public async Task UpdateApplication(ApplicationDTO applicationDTO)
{
      var visitors = Mapper.ToVisitors(applicationDTO.ApplicationVisitors);
      var visitorsToCreate = visitors.Where(w => w.Id == 0).ToList();
      var createdVisitors = visitors.Where(w => w.Id > 0).ToList();

      var resultCreateVisitors = await _wrapper.Visitor.CreateVisitorsAsync(visitorsToCreate);
            createdVisitors.AddRange(resultCreateVisitors);

      applicationDTO.ApplicationVisitors = Mapper.ToVisitors(createdVisitors);

      await _wrapper.Application.UpdateAsync(Mapper.ToApplication(applicationDTO));
}

Repository method

public async Task UpdateAsync(Application application)
{
      Update(application);
      await SaveAsync();
}

BaseRepository

public void Update(T entity)
{
      _repositoryContext.Set<T>().Attach(entity);
      _repositoryContext.Entry(entity).State = EntityState.Modified;
}

public async Task SaveAsync()
{
      await _repositoryContext.SaveChangesAsync();
}

I have not any exeption in debug. Application was filled by ID, but Platform and Visitor in collections ApplicationPlatforms and ApplicationVisitors does not filling by foreign key. References is existing in classes. view result Attach

Application

public class Application
{
    public int Id { get; set; }
    [Column(TypeName="date")]
    public DateTime DateStart { get; set; }
    [Column(TypeName = "date")]
    public DateTime DateEnd { get; set; }
    public int ApproverId { get; set; }
    public User Approver { get; set; }
    public int StatusId { get; set; }
    public ApplicationStatus Status { get; set; }
    public string VisitPurpose { get; set; }
    public DateTime CreatedAt { get; set; }
    public int AuthorId { get;set; }
    public User Author { get; set; }
    public IList<Draft> Drafts { get; set; }
    public IList<ApplicationVisitor> ApplicationVisitors { get; set; }
    public IList<ApplicationPlatform> ApplicationPlatforms { get; set; }
    public IList<Pass> Passes { get; set; }
}

ApplicationVisitor

public class ApplicationVisitor
{
    public int ApplicationId { get; set; }
    [ForeignKey("ApplicationId")]
    public Application Application { get; set; }
    public int VisitorId { get; set; }
    [ForeignKey("VisitorId")]
    public Visitor Visitor { get; set; }
}

ApplicationPlatform

public class ApplicationPlatform
{
    public int ApplicationId { get; set; }
    [ForeignKey("ApplicationId")]
    public Application Application { get; set; }
    public int PlatformId { get; set; }
    [ForeignKey("PlatformId")]     
    public Platform Platform { get; set; }
}

UPD: 22.10.2019. This is my solution what working for me on base selected answer!

I rewrited update method in ApplicationRepository

public async Task UpdateAsync(Application application)
{
    var app = await GetAsync(application.Id);

    app.DateStart = application.DateStart;
    app.DateEnd = application.DateEnd;
    app.ApproverId = application.ApproverId;
    app.StatusId = application.StatusId;
    app.VisitPurpose = application.VisitPurpose;
    app.CreatedAt = application.CreatedAt;
    app.AuthorId = application.AuthorId;
    app.ApplicationVisitors = application.ApplicationVisitors;
    app.ApplicationPlatforms = application.ApplicationPlatforms;

    Update(app);
    await SaveAsync();
}

And rewrided method in my BaseRepository

public void Update(T entity)
{
    _repositoryContext.Set<T>().Update(entity);
}
1
0
10/22/2019 9:56:37 AM

Accepted Answer

Although you attached the Application object and set its state to Modified, all other objects references by it will be in Unchanged state, as stated here:

For entity types with generated keys if an entity has its primary key value set then it will be tracked in the Unchanged state. If the primary key value is not set then it will be tracked in the Added state. This helps ensure only new entities will be inserted. An entity is considered to have its primary key value set if the primary key property is set to anything other than the CLR default for the property type.

You can either manually set the state of all referenced objects or, A better approach in my option, is to load the objects from the database (and have EF track them for changes) and modify these objects. These way EF will know the exact state for each object when it comes to save it to the database.

1
10/22/2019 5:48:53 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow