An object with the same key already exists in the ObjectStateManager - c#

I have a scenario that could not find the solution for it and need some help
How can I achieve this,
I’d like to get current record for the client modify it and instead of update I’d like to add the new record to table for historical change information
client c = new client();
using (DBEntities db = new DBEntities())
{
// get current records in the client table for client
IQueryable<client> co = from p in db.client where p.CUS_NUMBER == scd.cus_number && p.isCurrent == true select p;
c = co.First();
//update email and and address
c.EMAIL = Helper.CleanInput("mymail#mm.com");
c.ADDRESS = Helper.CleanInput("123 Sheppard");
//instead of updating current record I'd like to add new record to the table to keep historical changes
db.AddToclient(c);
db.SaveChanges();
//I get error that
//An object with the same key already exists in the ObjectStateManager.
//The existing object is in the Modified state. An object can only be added to
//the ObjectStateManager again if it is in the added state.
Complete error
An object with the same key already exists in the ObjectStateManager. The existing object is in the Modified state. An object can only be added to the ObjectStateManager again if it is in the added state.

remove this code db.AddToclient(c); ,rest all is fine,You are already accessing the object by its reference so no need to add it again.It'll get modified when you call savechanges()
or use cloning if you want to add new object c = co.First().Clone();

It's look like you are adding same row to database and error is coming due to addition of same row again having same primary key which DB will not allow.
Try to add new row and make another table that keeps Historical information of old row and a reference as foreign key. You can add a boolean field that keep information regarding deletion let It is IsDeleted.
Hope It will Help
Thanks

The reason db.AddToclient(c); gives the error is because this object is being tracked by the object context, by possibly being in the database.
The best way to accomplish what you are trying to do is something like the following:
var newClient = new client()
{
EMAIL = Helper.CleanInput("mymail#mm.com"),
ADDRESS = Helper.CleanInput("123 Sheppard"),
};
db.AddToclient(newClient);
db.SaveChanges();

In Entity Framework, all objects retrieved from database by default are tracked by ObjectContext instance. Entity Framework internally maps all objects being tracked by his Key. This pattern is called Identity Map. This means that there will be only one instance of an entity per key. So, you don't need to call Add again, since the entity is already on EF map. You just need call SaveChanges to persist modified entities.
In your case you are:
1 - Creating a new instance of EF ObjectContext;
2 - Retrieving entities in your LINQ query;
3 - Changing values of properties of the retrieved entity;
4 - Adding again to the ObjContext; //error!
5 - Calling SaveChanges()
Step 4 is not necessary because the ObjectContext already knows about the retrieved objects.

Related

Cannot insert explicit value for identity column in table 'TABLE' when IDENTITY_INSERT is set to OFF Exception Updating my table

I´m trying to update a list of objects, but when I run context.SaveChanges(), I get an error
Cannot insert explicit value for identity column in table 'TABLE' when IDENTITY_INSERT is set to OFF
I know when the Identity key is generated you cannot register a new entry with this KEY but I'm trying to update my registry not insert a new one and this exception appears. I don't know why this happens now.
My code:
foreach (int i in deletes)
{
var p = context.Item.FirstOrDefault(g => g.participant_id == i);
if (p != null)
{
p.group_id = 0;
context.Entry(p).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
context.SaveChanges();
}
}
group_id is not my identity column, it is just another column I added:
ALTER TABLE Items
ADD group_id INTEGER DEFAULT(0);
The error specifically is the result of a configuration mismatch somewhere in your entity definitions where a table is set to use an Identity PK but EF is not configured for an identity column and the DbContext is attempting to insert a row into that table. This is not necessarily the table you think the DbContext is attempting to update. Chances are somewhere prior to SaveChanges being called there has been an entity incorrectly created or associated and treated as a new entity.
Try this, provided your code is roughly identical to your example:
using (var tempContext = new YourAppDbContext())
{
foreach (int i in deletes)
{
var p = tempContext.Item.FirstOrDefault(g => g.participant_id == i);
if (p != null)
p.group_id = 0;
}
tempContext.SaveChanges();
}
Here we isolate this operation to a clean, temporary DbContext instance to ensure there are no polluting tracked changes. This is not a "fix" for the issue, just to identify whether the context was polluted. You can inspect context pending changes to see what it might be tracking. (ChangeTracker) Your issue may also stem from setting the entire entity to Modified state and a misconfigured related entity definition. (unlikely if the entity and associated were read from this DbContext instance) When updating an entity, don't set the EntityState to Modified. This sets EF up to effectively update all columns on that table. In the above example if we just update 1 column, EF will generate an Update statement for just that single column, and will only generate an update statement if that value actually changes.
If the above code works without an issue, then you have rogue tracked changes polluting your DbContext. This either means you have something else going on before this code is called that you need to fix, or your DbContext lifetime scope is far longer than it should be. (or both)
The problem with your example is that we cannot see the scope that your context is covering. Whenever you make any kind of change to a DbContext, those changes are tracked by default by that DbContext. If you have code that is working with detached entities anywhere that suddenly get re-associated with a DbContext via association with an Added entity and treated as new entities themselves, then calling SaveChanges() when you expect to update a single row all the sudden results in strange unrelated exceptions because the DbContext wants to persist queued up changes.
A typical culprit to look out for with issues like this would be first to check over all of your entity definitions for tables using Identity PKs and ensure those entities are configured with DatabaseGeneratedOption.Identity. This alone would prevent the exception, but you'd probably find that EF would be inserting new, duplicate rows somewhere with new PKs. The culprit behind that is usually detached entities being re-associated to an entity.
Given a Order entity associated to a Product. We want to create an order so since we already loaded the Products collection to select and associated to the new Order, we set that reference client side and send the Order to the server. We assume that since we loaded the Products and it's children from a DbContext on a GET, that when we call POST and send that parent back to the server, all should be good.
public void CreateOrder(Order order)
{
context.Orders.Add(order);
context.SaveChanges();
}
order had a Product reference with ProductId = 22 since we selected product #22 for the order. However, the DbContext instance when we call CreateOrder doesn't know Product ID 22 represents a known entity, it isn't tracking Product ID 22, so it gets treated as a new entity. If the Product entity ID isn't configured as an Identity column but is in the DB, you get the error you saw. If it is configured as an Identity column then you'd find the Order saves successfully, but is pointing at a new, duplicate Product with an ID of 56 or whatever the next available ProductId is.
Passing detached entities is a big cause of headaches like this. The safe way to do something like the CreateOrder would be:
public void CreateOrder(Order order)
{
// TODO: Obviously add null checks, validations, etc.
var product = context.Products.Single(x => x.ProductId == order.Product.ProductId);
order.Product = product; // replace with the product tracked by this DbContext.
context.Orders.Add(order);
context.SaveChanges();
}
All associations on a detached entity need to be checked.
Devs don't like the hit to the database so they can be tempted to merely attach the Product:
public void CreateOrder(Order order)
{
// TODO: Obviously add null checks, validations, etc.
context.Products.Attach(order.Product);
context.Orders.Add(order);
context.SaveChanges();
}
.. and in most cases that will appear to work. Until it doesn't. Attach will throw an exception the moment you attempt to attach an entity with an ID that the DbContext is already tracking. If any code prior had loaded or attached an instance of that Product, then the call will fail. This can result in random-like exceptions appearing at runtime. The safe way to attach the entity would be:
public void CreateOrder(Order order)
{
// TODO: Obviously add null checks, validations, etc.
var existingProduct = context.Product.Local.SingleOrDefault(x => x.ProductId == order.Product.ProductId);
if (existingProduct == null)
context.Products.Attach(order.Product);
else
order.Product = existingProduct;
context.Orders.Add(order);
context.SaveChanges();
}
This checks the local tracking cache to see if the DbContext is tracking that product. (Does not hit DB) If it isn't then we can safely attach it. If it is, we replace the product reference on the order with the tracked one.
This would have to be done for every reference. Any that are missed would result in potential errors or duplicate rows.
Try
var p = context.DbSet<Participant>().Where(g => g.participant_id == i).FirstOrDefault();
And did you check your Participant class in EF? It still can be a foreign key there.

Deleting EF Core entity via Id using attach/remove results in InvalidOperationException

I have an EF Core database context set up that has a particular set of objects. I want to be able to delete these objects from my database via their Id. However I don't want to query the database and extract these objects as they're quite big and I'm trying to avoid the performance overhead.
Looking at this link it seems like a simple enough procedure. Find your Ids, create temporary objects of the same type and then attach them to the context, then remove them.
However when I do this, I get the following exception.
The instance of entity type 'Type' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked.
I assume this means that because there is already an instance of the object being tracked, I can't then load a second instance of the object into memory using the same id.
How then can I delete these objects using their Id? Loading the original database objects into memory is completely out of the question.
var policySetIdsToDelete = _configDbContext.PolicySets
.Where(ps => ps.SerialNo == serialNumber.ToUpper())
.OrderByDescending(ps => ps.Created).Skip(5).Select(ps => ps.Id.ToString()).ToList();
foreach (var id in policySetIdsToDelete)
{
var policySet = new PolicySet
{
Id = new Guid(id)
};
_configDbContext.PolicySets.Attach(policySet);
_configDbContext.PolicySets.Remove(policySet);
}
_configDbContext.SaveChanges();
You can use:
_configDbContext.Database.ExecuteSqlCommand
or try
_configDbContext.PolicySets.RemoveRange
You can inspire also from this article Entity Framework. Delete all rows in table

Entity Framework Core1.1 - Bulk Insert or Update - InvalidOperationException

I'm running into a problem with inserting OR updating roughly 950 entities.
var coins = JsonConvert.DeserializeObject<List<Currency>>(json);
var sw = new Stopwatch();
sw.Start();
using (var ctx = CryptoContext.Get)
{
var existingCoins = ctx.Coins.ToList();
foreach (var coin in coins)
{
var existing = existingCoins.FirstOrDefault(c => c.CMC_Id == coin.CMC_Id);
if (existing != null)
{
ctx.Entry<Currency>(coin).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
} else
{
ctx.Entry<Currency>(coin).State = Microsoft.EntityFrameworkCore.EntityState.Added;
}
}
ctx.SaveChanges();
var el = sw.ElapsedMilliseconds;
}
The code runs in the background of my netcoreapp1.1, with SQLite, and retrieves a list of currencies. This is done every 5 minutes with FluentScheduler. Because they're not entirely large objects I do all comparisons in memory, and try to add or update each one. My entity has a database-given ID of Id, and the API I'm retrieving from guarantees that CMC_Id is unique.
The initial insertion works fine. I get an error on the second "Update". I believe what's happening is that I'm tracking multiple entities as modified that each have an Id of 0
I was trying to follow this: https://msdn.microsoft.com/en-us/library/jj592676(v=vs.113).aspx
And the error I get is: "The instance of entity type 'Currency' cannot be tracked because another instance of this type with the same key is already being tracked. When adding new entities, for most key types a unique temporary key value will be created if no key is set (i.e. if the key property is assigned the default value for its type). If you are explicitly setting key values for new entities, ensure they do not collide with existing entities or temporary values generated for other new entities. When attaching existing entities, ensure that only one entity instance with a given key value is attached to the context."
I am unsure how to proceed with updating each row.
Issue here multiple entities with same key are asked to be tracked.
When you set EntityEntry.State to something then EF Core will start tracking the entity in the specific state. Since in your code, you are querying the database to find out existing entity, EF Core will start tracking the entity with given key therefore it throws above exception while setting the EntityEntry.State because there is already entity with same key being tracked.
More precisely you are trying to AddOrUpdate. There are multiple ways to achieve the behavior. Which one is the best depends on if you are adding one entity without relation or a complex graph.
The simplest method would be to just check existence instead of tracking the entity from database. Options for that would be to use AsNoTracking in your query so that EF does not start tracking it. Even more optimized way would be to just get count from database. If you are querying on PK property then count will be either 0 (non-existent) or 1 (existing entity). If it does not exist then you call Add otherwise Update.
var updatedBlog = new Blog { Id = 1, Title = "Updated" };
var exist = db.Blogs.Count(b => b.Id == updatedBlog.Id) != 0;
if (exist)
{
db.Update(updatedBlog);
}
else
{
db.Add(updatedBlog);
}
db.SaveChanges();
Since Add or Update methods start tracking whole graph, if your graph is in one consistent state, (all entities are new or all are being modified) then it would work just fine.
If your graph is somewhat inconsistent that state of each node in graph can be different (e.g. Updating a blog but it has new posts). Then you should use EntityEntry.State on individual entity. This makes sure that state is applied to only given entity and no other related entity in graph. Though you need to do above kind of check for each node in the graph. Another alternative is to use Attach method to attach whole graph in Unchanged state and then set state for individual node.
If you are having auto-generated Key values then probably you will have PK value set only when it is update else it would be CLR default. For single entity without relations, you can make that check yourself instead of querying database like above code and make decision. For graphs, you can use
db.ChangeTracker.TrackGraph(updatedBlog, n => n.Entry.State = n.Entry.IsKeySet ? EntityState.Modified : EntityState.Added);
This will set state of each node based on PK value being set or not.
Hope this helps :)

Prevent Entity Framework to automatically attach entities

I'm using the Entity Framework, and it's entities are used are Database representation AND business object.
So it means that some entities that are manipulated should always stay detached from the context.
I managed to read and write data from the database but I have a small problem when updating:
I have a table "Stock" which is linked to one table "Warehouse".
The current process is this one (simplified, but the spirit remains, there are more fields):
a new object Stock is created and its fields are filled with some values (date...)
the current Warehouse (object pulled for the entire request from the database) is associated to the Stock object
the object is sent to the DAL method which work is to save it.
The DAL method checks if the Stock item already exist for the day (same date, depot and same type) in the database
If it exist, the method updates the volume from the pulled object and save the changes.
Else, the new Stock object is inserted.
The problem here is that when I create the new Stock object and associate it to the Warehouse, the object EntityState is automatically set to "Added". So when I perform a SaveChanges() and the Stock already exist, the line is updated AND a new Stock line is added...
What I would want is to keep the new Stock object Detached until I attach it myself. I don't want that it happens automatically.
The only solution I found is to Detach the new object from the context before saving if the object already exist.
I could also Detach() the Warehouse object but that's not a satisfying solution I think as in the real case there are more items to associate and I'm not sure that's a good idea to play with Attach() and Detach() on them.
In this case, until I "Add" it to the context myself, the object is only a "Transport" object and I'd like it to stay out of the context.
Any idea on how I could keep the Stock object detached ?
Code (it may be a little incorrect, I wrote it by memory) :
Stock stk = new Stock();
stk.Date = DateTime.Now;
stk.Volume = 100; //so far stk is "Detached" and that's cool.
stk.Warehouse = CurrentWarehouse; //stk become "Added" and that's less cool.
DAL.Stock.Instance.Save(stk);
In Save():
var existing = (from s in Context.CurrentContext.Stock
where s.Warehouse.WarehouseId == stk.Warehouse.WarehouseId && s.Date == stk.Date && s.Type == 2
select s).FirstOfDefault();
if(existing != null)
{
existing.Volume = stk.Volume;
Context.CurrentContext.Detach(stk); //I find it a stupid workaround !!!!!!
}
else
{
Context.CurrentContext.AddToStock(stk); //what I would want to do.
}
Context.CurrentContext.SaveChanges()
You probably just want to set the MergeOption to an appropriate value. NoTracking would keep everything in a detached state, and allow you to perform your manual work. There are probably other ways to do this, but I'm doing something similar by setting MergeOption to detached.
http://msdn.microsoft.com/en-us/library/system.data.services.client.dataservicecontext.mergeoption.aspx

Why is LINQ to SQL entity association creating a new (duplicate) row when inserting a new record?

I am trying to insert a new entity using LINQ-to-SQL, and entity is associated with a User entity. The insert of the new entity is successful, but my existing User entity gets inserted as if it were a new User. The code looks something like the following:
var someEntity = new Entity();
someEntity.User = this.User;
dataContextInstance.SomeEntities.InsertOnSubmit(someEntity);
dataContextInstance.SubmitChanges();
Does anyone know why the user is being inserted as a brand new entity into the Users table? It would seem that the User.UserId would become the foreign key value in the UserId column of the row mapped to the someEntity that is being inserted.
Thanks for any help/suggestions/comments
Since the User entity has been previously loaded by another DataContext (which should hopefully be disposed by now!), you have to attach it to the new (current) DataContext otherwise the DataContext will view it as a new Entity and not an existing one (which already exists in the DB).
Make sure you're using the same instance of DataContext for both tables. See my question here for (I think) a clearer explanation of the problem.
Sorry, I don't get it? Do you want to update your existing user? What is someEntity for?
It makes sense, that LINQ tries to Insert a New user, because you tell it to do so. If you just want to change one of your users you need to select him out of SomeEntities, do the update and then call SubmitChanges (LINQ will recognize, that the original entity has been modified) - without .InsertOnSubmit.

Categories

Resources