entity records not updating - c#

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

Related

EF add List of entites to an existing entity

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.

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

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 Framework Pass Object from One Context to Another

I am new to Entity Framework so please bear with me.
I have a program that I want to select multiple records from a table and store it in a queue:
private Queue<RecordsToProcess> getRecordsToProcess()
{
Queue<RecordsToProcess> results = new Queue<RecordsToProcess>();
using (MyEntity context = new MyEntity())
{
var query = from v in context.RecordsToProcess
where v.Processed == false
select v;
foreach (RecordsToProcess record in query)
{
results.Enqueue(record);
}
}
}
Then I spin up multiple worker threads. Each worker thread takes one of the items in queue, processes it, and then saves it to the database.
private void processWorkerThread(object stateInfo)
{
while (workQueue.Count > 0)
{
RecordToProcess record = new RecordToProcess;
lock(workQueue)
{
if (workQueue.Count > 0)
RecordToProcess = workQueue.Dequeue();
else
break;
}
//Do the record processing here
//How do I save that record here???
}
}
My understanding is that to save changes back to the database you just call context.SaveChanges() but I can't do that in this situation can I?
Any help is appreciated.
Thanks!
Since you are disposing your MyEntity context in the first method (by wrapping it in a using statement), the entities that are enqueued will be in a "detached" state. That means, among other things, that changes done to the entity will not be tracked and you will not be able to lazy load navigation properties.
It is perfectly fine to dequeue these entities, "attaching" them to a different context, update them, and then call SaveChanges to persist the changes.
You can read about Attaching and Detaching Objects and Add/Attach and Entity States
It might be safer if you save off the primary key in the queue instead and retrieve the entities again. This way you are more likely avoid any data concurrency issues.

Adding and deleting many-to-many using DbContext API

I am using Entity Framework and DbContext API do build my application but I am having trouble working with objects with many-to-many relations. A simplified save-method could look like this
public void MyObj_Save(MyObj myobj)
{
DbContext.Entry(myobj).State = EntityState.Added;
DbContext.SaveChanges();
}
This code works fine, but if MyObj contains a many-to-many relation this is not saved. I know from using the old POCO API, that I needed to attach the related objects to the context but I cannot find a way to do this correctly with the DbContext API - a simplified example below
public void MyObj_Save(MyObj myobj, List<OtherObj> otherObjList)
{
foreach (OtherObj otherObj in otherObjList)
{
DbContext.OtherObj.Attach(otherObj);
myobj.OtherObj.Add(otherObj);
}
DbContext.Entry(myobj).State = EntityState.Added;
DbContext.SaveChanges();
}
I get no error, but the relations are not saved. What to do?
I quote your (important!) comment:
The objects I send to the method are attached and EntityState is
Unchanged. The configuration of my DbContext is, that I have disabled
AutoDetectChangesEnabled...
So, your code would look like this:
DbContext.Configuration.AutoDetectChangesEnabled = false;
DbContext.Entry(myobj).State = EntityState.Unchanged;
foreach (OtherObj otherObj in otherObjList)
DbContext.Entry(otherObj).State = EntityState.Unchanged;
// entering MyObj_Save method here
foreach (OtherObj otherObj in otherObjList)
{
//DbContext.OtherObj.Attach(otherObj); // does not have an effect
myobj.OtherObj.Add(otherObj);
}
DbContext.Entry(myobj).State = EntityState.Added;
DbContext.SaveChanges();
And this indeed doesn't work because EF doesn't notice that you have changed the relationship between myobj and the list of OtherObj in the line myobj.OtherObj.Add(otherObj); because you have disabled automatic change detection. So, no entries will be written into the join table. Only myobj itself will be saved.
You cannot set any state on an entity to put the state manager into a state that the relationship is saved because it is not an entity state which is important here but a relationship state. These are separate entries in the object state manager which are created and maintained by change detection.
I see three solution:
Set DbContext.Configuration.AutoDetectChangesEnabled = true;
Call DetectChanges manually:
//...
DbContext.Entry(myobj).State = EntityState.Added;
DbContext.ChangeTracker.DetectChanges();
DbContext.SaveChanges();
Detach the new myobj from the context before you set it into Added state (this feels very hacky to me):
// entering MyObj_Save method here
DbContext.Entry(myobj).State = EntityState.Detached;
foreach (OtherObj otherObj in otherObjList)
//...
Maybe it is possible - by getting to the ObjectContext through the IObjectContextAdapter - to modify the relationship entries in the object state manager manually but I don't know how.
In my opinion, this procedure to manipulate entity (and relationship) states manually is not the way you are supposed to work with EF. AutoDetectChangesEnabled has been introduced to make working with EF easier and safer and the only recommended situation to disable it is a high performance requirement (for example for bulk inserts). If you disable automatic change detection without need you are running into problems like this which are difficult to detect and it requires advanced knowledge of EF's inner workings to fix those bugs.
public void MyObj_Save(MyObj myobj, List<OtherObj> otherObjList)
{
DbContext.Entry(myobj).State = EntityState.Added;
foreach (OtherObj otherObj in otherObjList)
{
(((System.Data.Entity.Infrastructure.IObjectContextAdapter)DbContext)
.ObjectContext)
.ObjectStateManager
.ChangeRelationshipState(myobj, otherObj,
q => q.OtherObjs, EntityState.Added);
}
DbContext.SaveChanges();
}
Again, it is a simplified and not a real life example!

Categories