216

I have a Service Object Update

public bool Update(object original, object modified) { var originalClient = (Client)original; var modifiedClient = (Client)modified; _context.Clients.Update(originalClient); //<-- throws the error _context.SaveChanges(); //Variance checking and logging of changes between the modified and original } 

This is where I am calling this method from:

public IActionResult Update(DetailViewModel vm) { var originalClient = (Client)_service.GetAsNoTracking(vm.ClientId); var modifiedClient = (Client)_service.Fetch(vm.ClientId.ToString()); // Changing the modifiedClient here _service.Update(originalClient, modifiedClient); } 

Here is the GetAsNotTracking method:

public Client GetAsNoTracking(long id) { return GetClientQueryableObject(id).AsNoTracking().FirstOrDefault(); } 

Fetch method:

public object Fetch(string id) { long fetchId; long.TryParse(id, out fetchId); return GetClientQueryableObject(fetchId).FirstOrDefault(); } 

GetClientQueryableObject:

private Microsoft.Data.Entity.Query.IIncludableQueryable<Client, ActivityType> GetClientQueryableObject(long searchId) { return _context.Clients .Where(x => x.Id == searchId) .Include(x => x.Opportunities) .ThenInclude(x => x.BusinessUnit) .Include(x => x.Opportunities) .ThenInclude(x => x.Probability) .Include(x => x.Industry) .Include(x => x.Activities) .ThenInclude(x => x.User) .Include(x => x.Activities) .ThenInclude(x => x.ActivityType); } 

Any ideas?

I have looked the following articles / discussions. To no avail:ASP.NET GitHub Issue 3839

UPDATE:

Here are the changes to GetAsNoTracking:

public Client GetAsNoTracking(long id) { return GetClientQueryableObjectAsNoTracking(id).FirstOrDefault(); } 

GetClientQueryableObjectAsNoTracking:

private IQueryable<Client> GetClientQueryableObjectAsNoTracking(long searchId) { return _context.Clients .Where(x => x.Id == searchId) .Include(x => x.Opportunities) .ThenInclude(x => x.BusinessUnit) .AsNoTracking() .Include(x => x.Opportunities) .ThenInclude(x => x.Probability) .AsNoTracking() .Include(x => x.Industry) .AsNoTracking() .Include(x => x.Activities) .ThenInclude(x => x.User) .AsNoTracking() .Include(x => x.Activities) .ThenInclude(x => x.ActivityType) .AsNoTracking(); } 
8
  • 6
    I think where you're putting AsNoTracking() might be a bit late, as _context.Clients is already being tracked. Try putting your AsNoTracking() directly on the _context.Clients call. All of your lncludes should probably be AsNoTracking() as well, unless you plan on tracking those. Commented Apr 26, 2016 at 5:41
  • @RobertHarvey trying it now. Will let you know. Commented Apr 26, 2016 at 5:43
  • @RobertHarvey I tried your suggestion. I added the AsNoTracking() to the _context call. Not working. Shall I update the question with my changes? Commented Apr 26, 2016 at 5:52
  • 1
    What happens if you call GetAsNoTracking for both modified and original? Commented Apr 26, 2016 at 6:24
  • 3
    For the record: one AsNoTracking() call is enough, no matter where. Commented Apr 26, 2016 at 11:43

25 Answers 25

145

Without overriding EF track system, you can also Detach the 'local' entry and attach your updated entry before saving :

// var local = _context.Set<YourEntity>() .Local .FirstOrDefault(entry => entry.Id.Equals(entryId)); // check if local is not null if (local != null) { // detach _context.Entry(local).State = EntityState.Detached; } // set Modified flag in your entry _context.Entry(entryToUpdate).State = EntityState.Modified; // save _context.SaveChanges(); 

UPDATE: To avoid code redundancy, you can do an extension method :

public static void DetachLocal<T>(this DbContext context, T t, string entryId) where T : class, IIdentifier { var local = context.Set<T>() .Local .FirstOrDefault(entry => entry.Id.Equals(entryId)); if (!local.IsNull()) { context.Entry(local).State = EntityState.Detached; } context.Entry(t).State = EntityState.Modified; } 

My IIdentifier interface has just an Id string property.

Whatever your Entity, you can use this method on your context :

_context.DetachLocal(tmodel, id); _context.SaveChanges(); 
Sign up to request clarification or add additional context in comments.

2 Comments

I am trying to do this in a generic repository in which I don't have access to the entity's primary key (which could have any name and be of any type). Is there a way of finding the locally tracked entity in this scenario? Clearly EF can do it internally but I can't find a public API for it.
Caveat; this code needs LanguageExt package for local.IsNull() ... <PackageReference Include="LanguageExt.Core" Version="4.2.1" />. The function isn't built into EF Core.
66

For me this just fixed the problem. Add this code before any update

_context.ChangeTracker.Clear() 

From Microsoft Documentation

Stops tracking all currently tracked entities.

DbContext is designed to have a short lifetime where a new instance is created for each unit-of-work. This manner means all tracked entities are discarded when the context is disposed at the end of each unit-of-work. However, clearing all tracked entities using this method may be useful in situations where creating a new context instance is not practical.

This method should always be preferred over detaching every tracked entity. Detaching entities is a slow process that may have side effects. This method is much more efficient at clearing all tracked entities from the context.

Note that this method does not generate StateChanged events since entities are not individually detached.

Update

Microsoft explanation of simple unit of work

Update

It is best to not call the Update() method. Just use the tracking feature when querying objects that needs to be modified then call SaveChanges() method which will update only the edited fields in an optimized way. That's how Tracking of EfCore works. Tracking is a good feature if it is used well.

If tracking is disabled in your project or for any other reason then use this method that I created. It is the optimized solution for updating object for EFCore. Call it instead of Update() Method of the DbContext and it will check if the object is tracked or not. If it tracked then it will do nothing. If object is not tracked then it will do the tracking work manually. Just call SaveChanges() method after and it will created the optimized SQL statement that will update only the fields that has been changed. This will also help you if you want to create an auditing feature to your app to track easily the changes of each row for all your data.

public void UpdateIfNoTracking(TEntity entityToUpdate) where TEntity : class { var keys = GetPrimaryKeys(context, entityToUpdate); bool tracked = context.Entry(entityToUpdate).State != EntityState.Detached; if (tracked) return; if (keys != null) { var oldValues = context.Set<TEntity>().Find(keys); context.Entry(oldValues).CurrentValues.SetValues(entityToUpdate); } else { context.Set<TEntity>().Attach(entityToUpdate); context.Entry(entityToUpdate).State = EntityState.Modified; } } 

I published the full solution library at Github:Solid.DataAccess which applies the Unit Of Work and Repository Pattern in a good way. I use it in all my projects and it works like charm. Feel free to clone and contribute to making it better.

GetPrimaryKeys() Method is for getting all the primary keys values of the object dynamicly since I'm using Generic object. That helps a lot when using composite or multiple primary keys for an entity.

 private static object[] GetPrimaryKeys<T>(DbContext context, T value) { var keyNames = context.Model.FindEntityType(typeof(T)).FindPrimaryKey().Properties .Select(x => x.Name).ToArray(); var result = new object[keyNames.Length]; for (int i = 0; i < keyNames.Length; i++) { result[i] = typeof(T).GetProperty(keyNames[i])?.GetValue(value); } return result; } 

6 Comments

Only avaliable on ef core 5.0 and above
this is what I needed since I am unit testing w/ an InMemory DB - so when adding things to then remove later I was getting the exception. +1 for saving me a few hours..
Thanks man !!!! Following a tutorial who is using EF InMemory, they don't use this sentence, so only the method UPDATE is not working in my RESTful environment. I spent a whole day trying to figure out how to make it work, until I found your post! Thank you !
GetPrimaryKeys method is missing in above code. pls explain the function GetPrimaryKeys()
Thanks @sabsab to update with explanation.
|
53
public async Task<Product> GetValue(int id) { Product Products = await _context.Products .AsNoTracking().FirstOrDefaultAsync(x => x.Id == id); return Products; } 

AsNoTracking()

Important: Using AsNoTracking() works like a charm in many contexts. However, unit tests will fail when using mocking or stubbing strategies with frameworks like Moq. Official explanation from MSDN:

However, properly mocking DbSet query functionality is not possible, since queries are expressed via LINQ operators, which are static extension method calls over IQueryable. As a result, when some people talk about "mocking DbSet", what they really mean is that they create a DbSet backed by an in-memory collection, and then evaluate query operators against that collection in memory, just like a simple IEnumerable. Rather than a mock, this is actually a sort of fake, where the in-memory collection replaces the real database.

Avoid future issues when trying to unit test with a mocking strategy. There are other ways of unit testing like implementing the repository pattern, as mentioned in the Microsoft documentation.

3 Comments

Worked for me...!
Worked like a charm.
AsNoTracking could bring a lot of issues when loading entity with many related entities.
22

In my case, the table's id column was not set as an Identity column.

1 Comment

you saved me :) I had my key set, but wrongly (Id and Level instead of only Id) and therefore I got this error exception.
11

I had the same issue (EF Core) while setting up xUnit tests. What 'fixed' it for me in testing was looping through the change tracker entities after setting up the seed data.

  • at the bottom of the SeedAppDbContext() method.

I set up a Test Mock Context:

/// <summary> /// Get an In memory version of the app db context with some seeded data /// </summary> public static AppDbContext GetAppDbContext(string dbName) { //set up the options to use for this dbcontext var options = new DbContextOptionsBuilder<AppDbContext>() .UseInMemoryDatabase(databaseName: dbName) //.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking) .Options; var dbContext = new AppDbContext(options); dbContext.SeedAppDbContext(); return dbContext; } 

Extension method to add some seed data:

  • and detach entities in foreach loop at bottom of method.
 public static void SeedAppDbContext(this AppDbContext appDbContext) { // add companies var c1 = new Company() { Id = 1, CompanyName = "Fake Company One", ContactPersonName = "Contact one", eMail = "[email protected]", Phone = "0123456789", AdminUserId = "" }; c1.Address = new Address() { Id = 1, AddressL1 = "Field Farm", AddressL2 = "Some Lane", City = "some city", PostalCode = "AB12 3CD" }; appDbContext.CompanyRecords.Add(c1); var nc1 = new Company() { Id = 2, CompanyName = "Test Company 2", ContactPersonName = "Contact two", eMail = "[email protected]", Phone = "0123456789", Address = new Address() { }, AdminUserId = "" }; nc1.Address = new Address() { Id = 2, AddressL1 = "The Barn", AddressL2 = "Some Lane", City = "some city", PostalCode = "AB12 3CD" }; appDbContext.CompanyRecords.Add(nc1); //....and so on.... //last call to commit everything to the memory db appDbContext.SaveChanges(); //and then to detach everything foreach (var entity in appDbContext.ChangeTracker.Entries()) { entity.State = EntityState.Detached; } } 

The controller put method

The .ConvertTo<>() Method is an extension method from ServiceStack

 [HttpPut] public async Task<IActionResult> PutUpdateCompany(CompanyFullDto company) { if (0 == company.Id) return BadRequest(); try { Company editEntity = company.ConvertTo<Company>(); //Prior to detaching an error thrown on line below (another instance with id) var trackedEntity = _appDbContext.CompanyRecords.Update(editEntity); await _appDbContext.SaveChangesAsync(); } catch (DbUpdateConcurrencyException dbError) { if (!CompanyExists(company.Id)) return NotFound(); else return BadRequest(dbError); } catch (Exception Error) { return BadRequest(Error); } return Ok(); } 

and the test:

 [Fact] public async Task PassWhenEditingCompany() { var _appDbContext = AppDbContextMocker.GetAppDbContext(nameof(CompaniesController)); var _controller = new CompaniesController(null, _appDbContext); //Arrange const string companyName = "Fake Company One"; const string contactPerson = "Contact one"; const string newCompanyName = "New Fake Company One"; const string newContactPersonName = "New Contact Person"; //Act var getResult = _controller.GetCompanyById(1); var getEntity = (getResult.Result.Result as OkObjectResult).Value; var entityDto = getEntity as CompanyFullDto; //Assert Assert.Equal(companyName, entityDto.CompanyName); Assert.Equal(contactPerson, entityDto.ContactPersonName); Assert.Equal(1, entityDto.Id); //Arrange Company entity = entityDto.ConvertTo<Company>(); entity.CompanyName = newCompanyName; entity.ContactPersonName = newContactPersonName; CompanyFullDto entityDtoUpd = entity.ConvertTo<CompanyFullDto>(); //Act var result = await _controller.PutUpdateCompany(entityDtoUpd) as StatusCodeResult; //Assert Assert.True(result.StatusCode == 200); //Act getResult = _controller.GetCompanyById(1); getEntity = (getResult.Result.Result as OkObjectResult).Value; entityDto = getEntity as CompanyFullDto; //Assert Assert.Equal(1, entityDto.Id); // didn't add a new record Assert.Equal(newCompanyName, entityDto.CompanyName); //updated the name Assert.Equal(newContactPersonName, entityDto.ContactPersonName); //updated the contact //make sure to dispose of the _appDbContext otherwise running the full test will fail. _appDbContext.Dispose(); } 

Comments

11

It sounds as you really just want to track the changes made to the model, not to actually keep an untracked model in memory. May I suggest an alternative approach which will remove the problem entirely?

EF will automatically track changes for you. How about making use of that built in logic?

Override SaveChanges() in your DbContext.

 public override int SaveChanges() { foreach (var entry in ChangeTracker.Entries<Client>()) { if (entry.State == EntityState.Modified) { // Get the changed values. var modifiedProps = ObjectStateManager.GetObjectStateEntry(entry.EntityKey).GetModifiedProperties(); var currentValues = ObjectStateManager.GetObjectStateEntry(entry.EntityKey).CurrentValues; foreach (var propName in modifiedProps) { var newValue = currentValues[propName]; //log changes } } } return base.SaveChanges(); } 

Good examples can be found here:

Entity Framework 6: audit/track changes

Implementing Audit Log / Change History with MVC & Entity Framework

EDIT: Client can easily be changed to an interface. Let's say ITrackableEntity. This way you can centralize the logic and automatically log all changes to all entities that implement a specific interface. The interface itself doesn't have any specific properties.

 public override int SaveChanges() { foreach (var entry in ChangeTracker.Entries<ITrackableClient>()) { if (entry.State == EntityState.Modified) { // Same code as example above. } } return base.SaveChanges(); } 

Also, take a look at eranga's great suggestion to subscribe instead of actually overriding SaveChanges().

4 Comments

I have actually looked at these examples; some issues that I got was that it needed to be enabled on certain tables. The use cases used there was a broad implementation. Thanks for the feedback. Really appreciate it.
this could get somewhere, thanks for the input. just one query, though -- how do I get the authorized user? I am needing it for the audit log. Can I use the User.GetUserId()?
That would depend on your application and how you authenticate the user. Is it WPF, ASP, MVC etc. I usually abstract it to a manager or util that can retrieve the current user. User.GetUserId() sounds like something that is available in the Controller, which is short for HttpContext.User. So you need HttpContext. Here's someting that will help you: stackoverflow.com/questions/1918283/…, stackoverflow.com/questions/5898170/…
HttpContext.Current.User.Identity.GetUserId();
6

For me, I was experiencing this issue while also using AutoMapper and .NET 6. To resolve it, I changed the code from:

DbItem? result = await _dbContext.DbItems.FirstOrDefaultAsync(t => t.Id == id); if (result == null) { return null; } DbItem mappedItem = _mapper.Map<DbItem>(dto); //problematic line var updatedItem = _dbContext.DbItems.Update(mappedItem); 

To:

DbItem? result = await _dbContext.DbItems.FirstOrDefaultAsync(t => t.Id == id); if (result == null) { return null; } _mapper.Map(dto, result); //the fix var updatedItem = _dbContext.DbItems.Update(result); 

The problematic line created a NEW DbItem with the same key value(s), leading to the issue. The fix line maps the fields from the DTO to the original DbItem.

2 Comments

Bingo! That was my issue.
And how would you deal with nested entities? For example {name: "item 1", SubItems: [{name: "SubItem1"}]}. Even if I do _mapper. Map(dto, result); the sub-items array will be replaced with objects with different references which is equal to _mapper.Map<DbSubItem>(x);
5

Had this problem too.. Solved it by untracking the old entity first before saving.

 public async Task<int> Update<T>(T entity) where T : BaseEntity { entity.UpdatedAt = DateTime.UtcNow; // Untrack previous entity version var trackedEntity = this.context.Set<T>() .SingleOrDefaultAsync(e => e.Id == entity.Id); this.context.Entry<T>(await trackedEntity).State = EntityState.Detached; // Track new version this.context.Set<T>().Attach(entity); this.context.Entry<T>(entity).State = EntityState.Modified; await this.context.SaveChangesAsync(); return entity.Id; } 

Comments

4

In EF core - also make sure that you dont set both the foreign key and the foreign key navigation property. I got this error when I set both the key and the property.

e.g.

 new VerificationAccount() { Account = konto_1630, VerificationRowType = VerificationRowType.Template, // REMOVED THE LINE BELOW AND THE ERROR WENT AWAY //VerificationAccount = verificationAccounts.First(x => x.Account == konto_1630), VerificationId = verificationId } 

Comments

4

You could just set the entity to detatched after saving, like this:

public async Task<T> Update(int id, T entity) { entity.Id = id; _ctx.Set<T>().Update(entity); await _ctx.SaveChangesAsync(); _ctx.Entry(entity).State = EntityState.Detached; //detach saved entity return entity; } 

3 Comments

Worked for me. I'm using .Net Core 3.0 in this application. I also had to set this in the constructor for my repository in order to make it work: DbContext.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
I'm getting an exception near the saveChanges method, ie.., before the line where I add Detached, any clue how to fix it ?
what kind of exception?
2

Just as the error message says, there're two entities being tracked. If you're doing an update operation:

  1. do a Get and get the entity
  2. update that entity by setting the properties of that entity. Do not do a new on the entity in question. This creates two entities.

1 Comment

Thanks! That was the correct answer in my case
0

I got this error from my background service. I solved which creating a new scope.

 using (var scope = serviceProvider.CreateScope()) { // Process } 

1 Comment

isn't this reducing the performance? I think it's bad to create a new service and inject all its dependencies just to update an entity.
0

This error message can happen if you have duplicate entries/entities and run SaveChanges().

3 Comments

This doesn't answer the question.
This is a true comment I inserted unique values and error disappeared.
Yep, I had to do a Distinct() first when looping through entities.
0

If you have setted two or more tables with 'Id' or columns name with the same column name, the easiest way is to change OnModelCreating method in the context class.

In this case I have to change the 'Id' to 'AbandonedCartId' and tell to entity that object has column name 'Id'

entity.Property(e => e.AbandonedCartId).HasColumnName("Id"); 

Example

public partial class AbandonedCart { public int AbandonedCartId { get; set; } public double? CheckoutId { get; set; } public int? AppId { get; set; } public double? CustomerId { get; set; } } 
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<AbandonedCart>(entity => { entity.Property(e => e.AbandonedCartId).HasColumnName("Id"); entity.Property(e => e.CreatedAt).HasColumnType("datetime"); entity.HasOne(d => d.App) .WithMany(p => p.AbandonedCart) .HasForeignKey(d => d.AppId) .HasConstraintName("FK_AbandonedCart_Apps"); }); } 

Comments

0

In my case it was a mistake of saving changes twice for a unit of work. I was using saveChangesAsync() so it did not occurr immediatly, but later.

Comments

0

I also had the same problem. I queried a record from my database, then modified the property, then the context.Update() failed because the entity was already tracked.

The correct way to to it in my case was that if I query an entity from the database, I can't call context.Update(), just the context.SaveChanges().

Hope this helps.

Comments

-1

Arhhh this got me and I spent a lot of time troubleshooting it. The problem was my tests were being executed in Parellel (the default with XUnit).

To make my test run sequentially I decorated each class with this attribute:

[Collection("Sequential")] 

This is how I worked it out: Execute unit tests serially (rather than in parallel)


I mock up my EF In Memory context with GenFu:

private void CreateTestData(TheContext dbContext) { GenFu.GenFu.Configure<Employee>() .Fill(q => q.EmployeeId, 3); var employee = GenFu.GenFu.ListOf<Employee>(1); var id = 1; GenFu.GenFu.Configure<Team>() .Fill(p => p.TeamId, () => id++).Fill(q => q.CreatedById, 3).Fill(q => q.ModifiedById, 3); var Teams = GenFu.GenFu.ListOf<Team>(20); dbContext.Team.AddRange(Teams); dbContext.SaveChanges(); } 

When Creating Test Data, from what I can deduct, it was alive in two scopes (once in the Employee's Tests while the Team tests were running):

public void Team_Index_should_return_valid_model() { using (var context = new TheContext(CreateNewContextOptions())) { //Arrange CreateTestData(context); var controller = new TeamController(context); //Act var actionResult = controller.Index(); //Assert Assert.NotNull(actionResult); Assert.True(actionResult.Result is ViewResult); var model = ModelFromActionResult<List<Team>>((ActionResult)actionResult.Result); Assert.Equal(20, model.Count); } } 

Wrapping both Test Classes with this sequential collection attribute has cleared the apparent conflict.

[Collection("Sequential")] 

Additional references:

https://github.com/aspnet/EntityFrameworkCore/issues/7340
EF Core 2.1 In memory DB not updating records
http://www.jerriepelser.com/blog/unit-testing-aspnet5-entityframework7-inmemory-database/
http://gunnarpeipman.com/2017/04/aspnet-core-ef-inmemory/
https://github.com/aspnet/EntityFrameworkCore/issues/12459
Preventing tracking issues when using EF Core SqlLite in Unit Tests

Comments

-1

I faced the same problem but the issue was very silly, By mistake I have given wrong relationship I have given relationship between 2 Ids.

1 Comment

But sometimes you need a relationship between two IDs, like when you want a UNIQUE index
-1
public static void DetachEntity<T>(this DbContext dbContext, T entity, string propertyName) where T: class, new() { try { var dbEntity = dbContext.Find<T>(entity.GetProperty(propertyName)); if (dbEntity != null) dbContext.Entry(dbEntity).State = EntityState.Detached; dbContext.Entry(entity).State = EntityState.Modified; } catch (Exception) { throw; } } public static object GetProperty<T>(this T entity, string propertyName) where T : class, new() { try { Type type = entity.GetType(); PropertyInfo propertyInfo = type.GetProperty(propertyName); object value = propertyInfo.GetValue(entity); return value; } catch (Exception) { throw; } } 

I made this 2 extension methods, this is working really well.

Comments

-1

Cant update the DB row. I was facing the same error. Now working with following code:

_context.Entry(_SendGridSetting).CurrentValues.SetValues(vm); await _context.SaveChangesAsync(); 

Comments

-1

I have had the same problem before and solved it by replacing AddDbContext with the AddDbContextFactory to the services container.

This is how I solved the issue:

Instead of registering AddDbContext, I registered AddDbContextFactory instead, like this:

public void ConfigureServices(IServiceCollection services) { services.AddDbContextFactory<YourApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("YourDatabaseConnectionString"))); } 

IMPORTANT REMINDER:

Do not register AddDbContext and AddDbContextFactory together because you will get a System.AggregateException: 'Some services are not able to be constructed...' exception. Use AddDbContextFactory instead.

Your ApplicationDbContext class must expose a public constructor with a DbContextOptions<YourApplicationDbContext> parameter like this:

public class YourApplicationDbContext : DbContext { public ApplicationDbContext(DbContextOptions<YourApplicationDbContext> options): base(options){} } 

The DbContextFactory factory can then be used through constructor injection like this:

private readonly IDbContextFactory<YourApplicationDbContext> dbContextFactory; public YourConstructor(IDbContextFactory<YourApplicationDbContext> dbContextFactory) { dbContextFactory = dbContextFactory; } 

or

public YourController(IDbContextFactory<YourApplicationDbContext> dbContextFactory) { dbContextFactory = dbContextFactory; } 

The injected factory can then be used to construct DbContext instances in the service code like this:

 using (var context = dbContextFactory.CreateDbContext()) { // your database CRUD code comes in here... for example: context.DatabaseTable.Update(suppliedModel); await context.SaveChangesAsync(); } 

When you may consider this option: Registering a factory instead of registering the context type directly allows you easy creation of new DbContext instances. It is also recommended for Blazor applications.

I hope this helps someone facing this issue. Cheers!

Comments

-1

I had this problem myself. Entity Framework keeps track of every object you insert into the database. So when you insert a duplicate record of the same object with a few fields being changed, EF will throw this error. I got around it by deep cloning the object I'm trying to re-insert, and it went through.

 public static T DeepClone<T>(this T a) { using (MemoryStream stream = new MemoryStream()) { BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(stream, a); stream.Position = 0; return (T)formatter.Deserialize(stream); } } 

then:

var cloned = objectYouAreTryingToReinsert.deepClone(); context.objects.add(cloned); await context.SaveChangesAsync(); 

1 Comment

This doesn't solve the issue. If an object with the same key is attached to the context you can't attach any other object (of the same class) with the same key, cloned or not.
-1

Extension method to detach entity for any key type.

public static void Detach<TEntry, TId>(this DbContext context, Func<TEntry, TId> idReader, TId id) where TEntry : class where TId : IEquatable<TId> { var local = context.Set<TEntry>() .Local .FirstOrDefault(entry => idReader(entry).Equals(id)); if (local != null) { context.Entry(local).State = EntityState.Detached; } } 

Usage for Guid key:

dbContext.Detach<EntryType, Guid>(e => e.Id, myEntity.Id); dbContext.Attach(myEntity); 

Comments

-1

For me, I have the same entity in navigation property.

e.g.

class Entity1 { public ICollection<Entity2> Entities2 { get; set; } // <-- problem } class Entity2 { public Entity1 Ent { get; set; } // <-- problem } 

Solution

Entity1 e = ... e.Entities2 = null; db.SaveChanges(); 

Comments

-2

If your data has changed every once,you will notice dont tracing the table.for example some table update id ([key]) using tigger.If you tracing ,you will get same id and get the issue.

1 Comment

Interessing can you explain better?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.