发布请求失败,因为实体说无法跟踪实体类型 'WorkEntry' 的实例,因为



我使用的是一个来自实体的InMemory DB,我一直有问题。有了下面的控制器,当我在id/workEntry路由上发帖时,我不断收到类似The instance of entity type 'WorkEntry' 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.的错误。

[Route("api/[controller]")]
public class ProjectsController : Controller
{
private readonly ApiContext _context;
public ProjectsController(ApiContext context)
{
_context = context;
}
[HttpGet]
[Route("{Id:int}")]
public string HelloWorld(int id)
{
return "Hello Back!";
}

// GET api/projects
[HttpGet]
public IActionResult Get() //async
{
return Ok(_context.Projects.Include(x => x.WorkEntries));
}
[HttpPost]
public async Task<IActionResult> Post([FromBody] Project prj)
{
try
{
if (prj != null)
{
Console.WriteLine("Post--->  " + prj.Id + " " + prj.Name + " " + prj.StartDate + " " + prj.EndDate );
_context.Projects.Add(prj);
await _context.SaveChangesAsync();
return Ok("Added new project with ID=" +prj.Id);
}
return BadRequest("Project is null");
}
catch (Exception e)
{
return BadRequest(e.Message);
}
}
//[HttpPut("{id}")]
[HttpPost]
[Route("{Id:int}/WorkEntry")]
public async Task<IActionResult> PostAsync(int id, WorkEntry workEntry)
{
try
{
if (workEntry != null)
{
Console.WriteLine("asta e WorkEntryyyyy---- " + workEntry);
var updatedProject = _context.Projects.Include(x => x.WorkEntries).First(x => x.Id == id);
Console.WriteLine(updatedProject.ToString());
updatedProject.WorkEntries.Add(workEntry);
_context.Projects.Attach(updatedProject);
await _context.SaveChangesAsync();
//db.Books.AddOrUpdate(book)
return Ok("project with ID=" + updatedProject.Id + " was updated");
}
return BadRequest("Project or WorkEntities is null");///schimba
}
catch (Exception e)
{
return BadRequest(e.Message);
}
}
}

有人知道我做错了什么吗?我尝试了使用AsNoTracking或更新的不同方法,但没有任何进展。任何提示对我都有好处:(

感谢

您不需要使用_context.Projects.Attach(updatedProject);,因为默认情况下,从数据库读取EntityFramework跟踪记录,并且当您将实体附加到Wntitifeamrwork跟踪的EntityFramework时,会发生错误

无法跟踪实体类型"WorkEntry"的实例,因为已经在跟踪另一个具有相同键值的实例

您应该删除_context.Projects.Attach(updatedProject);或使用.AsNoTracking()来修复此错误。

  1. 删除.Attach(updatedProject);
var updatedProject = _context.Projects.Include(x => x.WorkEntries).First(x => x.Id == id);
Console.WriteLine(updatedProject.ToString());
updatedProject.WorkEntries.Add(workEntry);
//_context.Projects.Attach(updatedProject);
await _context.SaveChangesAsync();
  1. 使用.AsNoTracking()
var updatedProject = _context.Projects.AsNoTracking().Include(x => x.WorkEntries).First(x => x.Id == id);
Console.WriteLine(updatedProject.ToString());
updatedProject.WorkEntries.Add(workEntry);
_context.Projects.Attach(updatedProject);
await _context.SaveChangesAsync();

Farhad的回答应该涵盖最可能的问题。另一件需要检查的事情是,它看起来像是在使用依赖注入,所以确保您的DbContext设置的生存期范围是Per-Request,而不是Singleton。

另一件事是,尚不清楚您是在尝试添加工作条目还是更新工作条目。您所拥有的代码(减去Attach(应该适用于Add场景。如果您想要更新,那么您应该将传入模型中的值复制到加载的&被跟踪实体。Automapper很方便在这里提供帮助:

var updatedProject = _context.Projects.Include(x => x.WorkEntries).Single(x => x.Id == id);
var existingWorkEntry = updatedProject.WorkEntries.SingleOrDefault(x => x.Id == workEntry.Id);
if (existingWorkEntry != null)
{
var config = new MapperConfiguration(cfg => cfg.CreateMap<WorkEntry, WorkEntry>());
var mapper = config.CreateMapper();
mapper.Map(existingWorkEntry, workEntry);
}
else // Include this if the method could receive a new Work Entry...
updatedProject.WorkEntries.Add(workEntry);
await _context.SaveChangesAsync();

请确保在POST调用中非常彻底地验证来自客户端的任何/所有数据,因为使用调试工具等可能会对其进行篡改。在客户端和服务器之间传递实体并将它们附加到设置的修改状态很容易被篡改,并且在内存使用方面效率非常低;传输有效载荷大小。Automapper的这种相同技术可以应用于使用更精简的ViewModel/DTO对象更新实体,从而将通过导线发送的数据减少到视图需要中继的数据,而不是整个实体。

相关内容

最新更新