使用OData与OwinSelfHost更新Person实体时遇上下文未跟踪错误
Hey there, fellow C# newbie! Let's break down why you're hitting that frustrating tracking error when updating your Person object—this is a super common gotcha with Entity Framework (which I assume you're using under the hood for your API service).
Why This Happens
The error means your DbContext doesn't recognize the Person object you're trying to update. The value parameter coming from your [FromBody] request is a brand-new instance created by deserializing the JSON payload—it's completely "detached" from your context, meaning the context isn't tracking any changes to it. When your api.updatePerson method tries to save this entity, EF throws an error because it can't track changes to something it doesn't know about.
Fixes to Try
Option 1: Fetch the Existing Entity First (Most Reliable)
This is the safest approach, especially if your Person has navigation properties or you want to validate the entity exists before updating. Modify your updatePerson method to:
- Load the existing
Personfrom the database (so the context starts tracking it) - Copy the updated values from your request object to the tracked entity
- Save the changes
public bool updatePerson(Person updatedPerson) { try { // Find the existing person using your primary key (assuming Id is your PK) var existingPerson = _context.People.Find(updatedPerson.Id); if (existingPerson == null) { // Person doesn't exist in the database return false; } // Copy all property values from the updated object to the tracked one _context.Entry(existingPerson).CurrentValues.SetValues(updatedPerson); // Save changes to the database _context.SaveChanges(); return true; } catch (Exception ex) { // Log the error for debugging (replace with your logging setup) Console.WriteLine($"Update failed: {ex.Message}"); return false; } }
Option 2: Attach the Detached Entity (For Performance)
If you don't want to hit the database twice (once to fetch, once to save), you can manually attach the request object to the context and mark it as modified. Just be sure the Id of your Person is valid and matches an existing record:
public bool updatePerson(Person updatedPerson) { try { // Attach the detached entity to the context _context.People.Attach(updatedPerson); // Tell EF the entire entity has been modified _context.Entry(updatedPerson).State = EntityState.Modified; _context.SaveChanges(); return true; } catch (Exception ex) { Console.WriteLine($"Update failed: {ex.Message}"); return false; } }
⚠️ Note: This approach can cause issues if you have navigation properties (EF won't track changes to those unless you handle them explicitly). Stick with Option 1 if your Person has related entities.
Quick Controller Improvement
Add a quick validation check at the start of your Put method to catch invalid data early:
[HttpPut] [Route()] public IHttpActionResult Put([FromBody]Person value) { // Validate the incoming data first if (value == null || value.Id == default) // Adjust based on your PK type (int, Guid, etc.) { return BadRequest("Invalid person data: missing or null object, or missing ID"); } Console.WriteLine("Value updated " + value.LastName); var result = api.updatePerson(value); return result ? Ok("Person updated") : BadRequest("An error occurred"); }
内容的提问来源于stack exchange,提问作者Dev

