如何复制现有DbSet实体并修改主键?解决会话线程报错问题
Solution for EF Entity Copy & Primary Key Modification Error
Hey there, let's break down why you're hitting that error and fix it properly—especially since your entity has tons of fields, we'll avoid manually mapping every property!
Why Your Current Code Fails
First, let's look at the root issues:
- Reference Assignment: When you do
PedidoMassPro_Detail newItem = item;, you're not creating a new entity—you're just pointingnewItemto the same object that EF's context is already tracking. ModifyingOrder_Numberhere would change the original entity's primary key, which is not what you want. - Delayed Execution + In-Loop SaveChanges: Your
Wherequery returns anIQueryable, which uses lazy loading. When you iterate over it in theforeach, EF is still actively reading from the database. CallingSaveChanges()inside the loop creates a transaction while another thread (the one enumerating the query) is still running in the same session—hence the error.
Fixes That Work (No Manual Property Mapping)
Option 1: Use EF's Built-in Value Cloning
This is the simplest approach if you just need to copy scalar properties (most cases):
// First, materialize the query to a List to avoid lazy loading conflicts var items = db.PedidoMassPro_Detail.Where(o => o.Order_Number.Equals(orderNumber)).ToList(); foreach(var item in items) { // Create a brand new instance of your entity PedidoMassPro_Detail newItem = new PedidoMassPro_Detail(); // Copy ALL scalar property values from the original item to the new one db.Entry(newItem).CurrentValues.SetValues(item); // Modify the primary key to your new value newItem.Order_Number = "TESTE111"; // Add the new entity to the context db.PedidoMassPro_Detail.Add(newItem); } // Save all changes at once (better performance + avoids session conflicts) db.SaveChanges();
SetValues()automatically copies every scalar property (like strings, numbers, dates) from the original entity to the new one—no need to writenewItem.Field1 = item.Field1;for every field!- Calling
ToList()upfront forces EF to load all matching entities into memory immediately, so the enumeration doesn't conflict with theSaveChanges()transaction.
Option 2: Use AutoMapper for Full Property Mapping (Including Navigations)
If your entity has navigation properties you need to copy too, AutoMapper is a great tool:
- First, install AutoMapper via NuGet if you haven't already.
- Configure the mapper and use it to clone your entity:
// Configure AutoMapper to map your entity to itself var mapperConfig = new MapperConfiguration(cfg => { cfg.CreateMap<PedidoMassPro_Detail, PedidoMassPro_Detail>(); }); var mapper = mapperConfig.CreateMapper(); // Materialize the query to a List var items = db.PedidoMassPro_Detail.Where(o => o.Order_Number.Equals(orderNumber)).ToList(); foreach(var item in items) { // Clone the entire entity (including navigation properties if configured) var newItem = mapper.Map<PedidoMassPro_Detail>(item); // Update the primary key newItem.Order_Number = "TESTE111"; db.PedidoMassPro_Detail.Add(newItem); } db.SaveChanges();
AutoMapper handles all property mapping automatically, even if you add new fields to your entity later—no need to update your cloning code.
Key Takeaways
- Always materialize your query with
ToList()before modifying/saving entities in a loop to avoid lazy loading conflicts. - Never assign an existing tracked entity to a new variable—always create a new instance and copy properties.
- Batch your
SaveChanges()calls (do it once after the loop) instead of calling it inside the loop—this is faster and avoids transaction issues.
内容的提问来源于stack exchange,提问作者Jairo Franchi
相关产品推荐
相关产品推荐

