1

How do I PUT a nested ICollection using ASP.Net Web API 2? I'll explain.

I'm using Entity Framework with Web API 2. I have a Company as follows:

public class Company
{
    public int ID { get; set; }

    [Required]
    public string Name { get; set; }

    ..

    public virtual CountryRegion CountryRegion { get; set; }
    public virtual ICollection<Organization> Organizations { get; set; }
}

I have the standard generated Web API 2 controller based of the Company model. Here is my PUT function:

// PUT api/Company/5
public IHttpActionResult PutCompany(int id, Company company)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

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

    var entityToUpdate = db.Companies.Find(id);
    db.Entry<Company>(entityToUpdate).CurrentValues.SetValues(company);
    db.Entry<Company>(entityToUpdate).State = EntityState.Modified;

    db.Entry<CountryRegion>(entityToUpdate.CountryRegion).CurrentValues.SetValues(company.CountryRegion);

    try
    {
        db.SaveChanges();
    }
    catch (DbUpdateConcurrencyException)
    {
        if (!CompanyExists(id))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    }

    return StatusCode(HttpStatusCode.NoContent);
}

Since db.Entry(company).State = EntityState.Modified; from the default generated PUT function does not work I have replaced that as discussed on another question as seen above.

When I send a PUT call like follows Name and CountryRegion save but not Organizations.

$.ajax({
    type: "PUT",
    url: "/api/company/2",
    data: {
        ID:2, 
        Name: "Test Company", 
        CountryRegion: {
            ID: 2, 
            Name: "United States"
        }, 
        Organizations: [
            {
                ID: 10,
                Name: "Test Org"
            },
            {
                ID: 22,
                Name: "Test Org 2"
            }
        ]
    }
});

How can I modify my controller code so that Organizations saves? Organization is many to many with Company. I thought perhaps I could just delete all of the existing Organizations associated to this Company and then save all the new ones but I'm then confused by how I can actually get those new Organizations to save and associate with the Company.

Community
  • 1
  • 1
bbodenmiller
  • 2,782
  • 5
  • 29
  • 48

2 Answers2

0

Just a shot in the dark, but are your FKs set up properly in the DB? I haven't used Entity Framework in years, but related objects not saving sounds like it could be an issue at that level, and not in your Web API.

Also, why is there no:

db.Entry<CountryRegion>(entityToUpdate.Organizations ).CurrentValues.SetValues(company.Organizations);

?

SethMW
  • 1,042
  • 1
  • 9
  • 10
  • Pretty sure it is correct. When I use the default POST method everything inserts correctly. I've tried that code snippet (with the correct type of Organization) but it gives an error since Organization is singular and I'm trying to put multiple hence the ICollection issue. – bbodenmiller Dec 25 '13 at 00:07
  • I've tried `db.Entry>(entityToUpdate.Organizations).CurrentValues.SetValues(company.Organizations);` which returns `The entity type HashSet1 is not part of the model for the current context.` while `db.Entry(entityToUpdate.Organizations).CurrentValues.SetValues(company.Organizations);` won't even build. – bbodenmiller Dec 25 '13 at 08:09
0

I was able to solve this using the following right above the try block however I'm not necessarily convinced this is the proper way to do it:

//remove current organizations
foreach (var organization in db.Organizations)
{
    entityToUpdate.Organizations.Remove(organization);
}
//add updated organizations
entityToUpdate.Organizations = company.Organizations;
bbodenmiller
  • 2,782
  • 5
  • 29
  • 48