EF add List of entites to an existing entity - c#

I am having an issue trying to add a list of entities to an existing entity.
Example -
My object Trade has a List offered and a List selected
When a trade is first created it contains a list of offered items. When someones selects items from the offered they are to be saved in the Selected field.
in my save i did the following
internal void acceptTrade(Trade trade)
{
using(var context = new datacontext())
{
Context.Entry(Trade).State = EntityState.Modified;
Trade.Status = "Accepted";
Foreach(selected)
{
Context.entry(selected).State = EntityState.Added;
}
Context.SaveChanges();
}
}
However, with this i get the following error
Attaching an entity of type item failed because another entity of the same type already has the same primary key value. This can happen when using the 'attach' method or setting the state of an entity to 'unchanged' or 'modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new
Ive tried to set each of the offered state to unchanged
internal void acceptTrade(Trade trade)
{
Context.Entry(Trade).State = EntityState.Modified;
Trade.Status = "Accepted";
Foreach(selected)
{
Context.entry(selected).State = EntityState.Added;
}
foreach(offered)
{
Context.Entry(offered).State = EntityState.Unchanged;
}
Context.SaveChanges();
}
and i still get the same error.
I even tried to use migrations by doing
db.set<Trade>().AddorUpdate(trade);
and no error occured but nothing was saved or modified.

Related

EF, Update doesnt work, it says Entities may have been modified or deleted since entities were loaded.

I am trying to create a layered MVC project but I am having an UPDATE problem in EF. I am getting the following error.
Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded.
I have DAL and BusinessLayer. In DAL, I have the following code for UPDATE
public void Update(params T[] entities)
{
using (var context = new BorselDBEntities())
{
foreach (T entity in entities)
{
context.Entry(entity).State = EntityState.Modified;
}
context.SaveChanges();
}
}
and this is how I call the DAL from BusinessLayer
public void UpdateProduct(params Product[] products)
{
_productRepository.Update(products);
}
Why am I getting the error above and what could I do to fix it?
One common reason is that context.Entry(entity) fails to get the entity which you want to update.
When you're debugging, see if context.Entry(entity) returns the entity; easily done by putting it on a separate line and setting a breakpoint afer:
public void Update(params T[] entities)
{
using (var context = new BorselDBEntities())
{
foreach (T entity in entities)
{
var myEntity = context.Entry(entity);
myEntity.State = EntityState.Modified;
}
context.SaveChanges();
}
}
If it's not, you'll need to work back through your code and work out why it's not able to pick it up. Often this will be because the identity/primary key column is not set on 'entity'.
E.g. in an MVC application, if you have an Edit/update form, remember to have a
#Html.HiddenFor(model => model.Id)
It is necessary to call the Attach method on the DbSet for the entity you are updating before you can change it's State. The local DbContext needs to contain the Entity or it will not know what changes to track.
https://msdn.microsoft.com/en-us/library/gg696261(v=vs.103).aspx

Struggling to implement a generic InsertOrUpdate() on DbContext

I am struggling to implement a very basic "InsertOrUpdate()" method on a DbContext. I tried following the advice in this post.
private static bool SaveItem<TEntity>(Object objToSave, TEntity existing = null) where TEntity : class
{
try
{
/////////////////////////////////////////
// BLOCK A
if(existing != null)
db.Set<TEntity>().Attach(existing);
/////////////////////////////////////////
db.Entry(objToSave).State = existing!=null ? EntityState.Modified : EntityState.Added;
db.SaveChanges();
} catch(Exception e)
{
Logger.Exception(e);
return false;
}
return true;
}
An example call to is the following:
SaveItem(item, db.MyInstances.Where(dbItem => dbItem.ID == item.ID).FirstOrDefault());
Some definitions:
class MyInstancesDbContext: DbContext { ... }
private static MyInstancesDbContext db = new MyInstancesDbContext();
As I understand it, in that call the .Where() will cause an attachment of some sort. So I've tried both including the small block of code labeled "A" and removing it. Both of which give me the same kind of error:
System.InvalidOperationException: Attaching an entity of type '...MyInstance' failed because a
nother entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any en
tities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the '
Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.
I found this popular related answer to this error where the user suggests using AsNoTracking(), but that instead makes me feel like I don't fundamentally understand something or am trying to ignore some error.
I'd greatly appreciate any advice.
I think what you're missing is that the DbContext tracks entities, and it doesn't like tracking entities of the same type with the same primary key.
When you call this:
db.MyInstances.Where(dbItem => dbItem.ID == item.ID).FirstOrDefault()
you've loaded an entity of MyInstance with primary key == item.ID into the context if it exists in the database.
This line is completely unneeded because existing would already be attached -- but that probably doesn't cause the error.
if(existing != null)
db.Set<TEntity>().Attach(existing);
The problem is probably here:
db.Entry(objToSave).State =
existing != null ? EntityState.Modified : EntityState.Added;
If existing == null, you might be okay, because this line will attach objToSave, but if existing exists, you'll have a problem because you'll be trying to attach objToSave which has the same type and primary key as existing.
Instead, you could try using objToSave to set the values for the attached entity:
db.Entry(existing).CurrentValues.SetValues(objToSave);
So objToSave will not be attached if there is an existing record.
https://msdn.microsoft.com/en-us/data/jj592677.aspx

Adding entity to DbContext not possible

I'm trying to copy an entity from one DbContext to another.
So I'm loading and detaching the entity before calling the save methods of the other DbContext.
EDIT:
First of all I'm loading the entity with the ID of the UserDT, then I'm detaching it from the old DbContext.
Finally I'l set SET IDENTITY_INSERT tUsers ON, save the entity and then turn SET IDENTITY_INSERT tUsers OFF.
var userEntity = DataContext.GetById<User>(id);
DataContext.EnsureDetached(userEntity);
offlineContext.ToggleIdentityInsert(true, typeof(User));
offlineContext.SetSaved(userEntity);
offlineContext.SaveChanges();
offlineContext.ToggleIdentityInsert(false, typeof(User));
Before DbContext.SaveChanges() I call this method (please note that this method is in a class inheriting from DbContext):
public T SetSaved<T>(T obj) where T : class, IEntity
{
var isNew = base.Set<T>().All(t => t.Id != obj.Id);
T ret = default(T);
var entry = Entry(obj);
if (isNew)
{
entry.State = EntityState.Added;
ret = base.Set<T>().Add(obj);
}
else
{
entry.State = EntityState.Modified;
}
return ret;
}
All entities I've used so far worked with this method.
Our User entity causes a NullReferenceException when calling this method, because the the properties CurrentValues and OriginalValues throw an InvalidOperationException saying that the entity is not attached to the current DbContext.
With this problem I can access the State and then add the obj to the DbContex.
EDIT:
I've forgot to say that the above code works on the second try. In my scenario I'm pressing the login button and the logged in user should be copied (offline DB). The first time I'll get the error, the second time I press the login button everything works fine.
Do you know what I could have forgotten?

Entity Framework 6: update entity already existing in ChangeTracker

I use repository with Update method. In this method I need to check some conditions, finding updating entity in DB before actual update. I use one context for both - Find and Update operations inside one transaction. But when I try to update entity I get an exception:
"Attaching an entity of type 'MyNamespace.MyEntityType' failed because another entity of the same type already has the same primary key value"
public void Update(SomeType entity)
{
using (var context = new MyEntities())
{
using (var transaction = context.Database.BeginTransaction(IsolationLevel.RepeatableRead))
{
try
{
// check conditions
var root = context.MyEntitySet
.Where(e => e.Parent == null); // entity.Parent == null
if(root ...)
; // return
// HERE I got an error described above
context.Entry(entity).State = EntityState.Modified;
context.SaveChanges();
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
}
}
}
I need to load entity with same Id from DB first, check some conditions and if ok, update entity. But after "Get" entity attaches to ChangeTracker with "Detached" state and when I try to change state to "Modified" I got an error.
I've already tried:
if (IsAttached(entity, out attachedEntity))
context.Entry(attachedEntity).CurrentValues.SetValues(entity);
but my original entity object stays unchanged with DB generated values. State = EntityState.Modified works as I need, but how can I remove preloaded entity from ChangeTracker?

entity records not updating

I have the following method:
public static void UpdatePpsTransaction(IEnumerable<PpsTransaction> ppsTransaction)
{
using (var context = PpsEntities.DefaultConnection())
{
foreach (var trans in ppsTransaction)
{
context.PpsTransactions.Attach(trans);
}
context.SaveChanges();
}
}
}
I was removing these records but I ended up creating a field IsProcessed which I am now setting to true. Now I am updating the records instead of deleting them, keeping them for record keeping.
Anyhow, I am not getting any errors but it is not updating the record.
Any suggestions?
You're not telling EF that you have made any changes, try to use the Entry method, on your Context:
public static void UpdatePpsTransaction(IEnumerable<PpsTransaction> ppsTransaction)
{
using (var context = PpsEntities.DefaultConnection())
{
foreach (var trans in ppsTransaction)
{
context.Entry(trans).State = EntityState.Modified;
}
context.SaveChanges();
}
}
This way, the entities will be attached to the context in a modified stated, so when you call SaveChanges(), these will be saved.
This will only work if the entities already exists in the database, which they should.
From msdn:
If you have an entity that you know already exists in the database but which is not currently
being tracked by the context then you can tell the context to track
the entity using the Attach method on DbSet. The entity will be in the
Unchanged state in the context. Note that no changes will be made to the
database if SaveChanges is
called without doing any other manipulation of the attached entity.
This is because the entity is in the Unchanged state.
Here is the link

Categories