SaveChanges doesn't save changes - c#

I have an application that loads all the data as expected using EF, however, when it comes to saving, I can't get it to work at all.
I've started off simple, by just using a value from a combobox to alter 1 field in the database. When the value is changed, it executes
this.t.Incident.AssignedTeamID = (int)this.cbTeam.SelectedValue;
I've also confirmed that this changed the EntityState to Modified and that the value is what I expect it to be. Despite this, calling
hdb.SaveChanges();
doesn't save anything back to the database. I know it's probably something simple I'm missing, but I cannot find out what that is at all.
Update:
Adding hdb.context.Attach(this.t.Incident); before using SaveChanges results in an InvalidOperationException stating "An entity object cannot be referenced by multiple instances of IEntityChangeTracker."
If it makes any difference, this is a desktop application, not a web application

Most likely, since you're working with a web app, you have a problem with a disconnected obect context. With all ORMs, you must go through an attach process to update an entity. SaveChanges will never work on both sides of the request/response.

Thank you to everybody who posted here. The answer was quite simple after reading these details.
What I needed to do, as Damien commented on the original question, was to ensure it was all loaded from the same class.
I currently created a private instance of the DB whenever needed, without really thinking. This was fine, it loaded the data as I expected, but meant that I would have around 3 different instances of the database loaded via different classes.
Essentially, I was trying to save the object from a different class with a different instance of the database. Moving the save method back to the class it was created from (presumably like it should have always been) resolved the issue.

Related

Grouping changes to save in Entity Framework Core

Im running a process that will affect a lot of records within a database for a user. I only want to apply all of the changes or none of them depending on the result of all of the changes. (e.g if one of the sub processes fail then no changes overall should take place). I also want to save notifications to the database to alert users of the outcome of the processes (e.g if a sub process fails then a notification is raised to let the user know that no changes were made due to reason x).
The best way I can think to do this is to detach all of the entries within the change tracker as they are added, then create notifications if something has succeeded or failed and save changes, then when it comes to applying all the changes I can iterate though the change tracker and reset the Entity State and save changes once more.
The issue i'm facing with this approach is that when it comes to reset the Entity State, I don't know whether the entity is Added or Modified. I could implement my own change tracker to store the previous state of the entity but it would make EF's change tracker redundant.
I could also only add all of the entity's right when I come to save them but that would require passing many objects down a chain link of nested methods right until the end.
Does anyone have any better suggestions or is it standard practice to use one of the mentioned hacks for this problem?
It sounds like you are trying to implement the Unit of Work pattern. The DbContext of EntityFramework makes this fairly easy to use, as the DbContext its self is the unit of work.
Just instantiate a new context and make the changes you need to it. You can pass the context around to any functions that make their changes. Once the "logical unit" operations are complete, call SaveChanges. As long as the individual methods do not call SaveChanges, you can compose them together in to a single unit, committed once the entire logical operation as finished. Everything will be committed atomically, within a single transaction. The data won't be left in an inconsistent state.
You told about transactions. Using Transactions or SaveChanges(false) and AcceptAllChanges()?
also you can implement versions of data in DB. as for me it will be more ease and correct way (you must always only insert data and never update. 1-to-many). in this case you can simply delete last records or mark them as unactive

NHibernate re-using identifiers when using session.SaveOrUpdate

I have a client who's been running a program of mine for a couple of years now who started getting strange errors.
My application throws exceptions with this in it:
Cannot insert duplicate key in object
Since I didn't touch the code in literally years, this confused me a lot.
And it only happened sometimes.
After A LOT of debugging and pulling out my hair, I figured out what is happening.
In the code that adds items to the database, I call session.SaveOrUpdate.
I can't recall a specific reason i chose this over the expected session.Save method, but let's continue. (i am changing this for the client's code though).
So what seems to be happening is that the SaveOrUpdate is re-using existing object's ID's and completely overriding the existing item. My code throws an error, but the new item is saved to the DB and there is no trace of the original record any longer. In my nhibernate mapping documents I am using the hilo generator for object IDs.
I am guessing this is only happening because there are now enough items in the DB to make the IDs restart or something, i don't know. I do have an audit table that has/had A LOT of records in it. 10,000's. But i truncated that table to make backups smaller. (could this have causes this problem).
I'm trying to find out if anyone can conclusively state if the SaveOrUpdate does for some reason re-use existing IDs or why changing the call to just Save works now. If this is a known issue i will sleep easy, if not, i need to further debug to see if there isn't still some situation where my client will lose data.
My code is running Nhibernate 3.3.3.4000, which was the latest code when i wrote this app.
Update 1
Session.Save is also re-using ID's.
I keep getting duplicate key errors, when inserting new records. But not every time, only some times. So it's quite random, which makes it hard to debug.
NHibernate users have requested a general purpose method that either saves a transient instance by generating a new identifier or update the persistent state associated with its current identifier. The SaveOrUpdate() method now implements this functionality.
http://nhibernate.info/doc/nh/en/index.html#manipulatingdata-updating-detached)
Based on this, you're hypothesis regarding the behaviour of SaveOrUpdate() would stand if NH allocated the object's key before testing whether or not it's 'transient' or 'persisted'. I.e. the key generator allocates a key that happens to be used and then the save or update logic favours update as it determine's the object is 'persistent'. I would be surprised if this is what's actually happening as it seems quite a basic mistake to make.
If you enable logging, you'll be able to determine whether this is actually the case or not.
I spent many hours to try and figure out this issue, but i sort of gave up in the end.
My solution, which seems to work so far, was to change the nhibernate id generator class from hilo to native.
This did require me to export and re-import all my data so that I could rebuild the tables however, so may not be a great solution for others who find this post, unless they change the identity on the tables manually.

Executing DeleteOnSubmit(), SubmitChanges(), InsertOnSubmit(), SubmitChanges() is not working (throws Entity Already exists Exception)!

I'm working on a WP7 mango App that makes use of Linq2SQL for data access.
I'm having a Note entity that has an Auto generated Key of type int.
The first time I add a new note to the db, the operation works fine, the note saves and then if I delete it from the db, it also gets removed from the db. The first entity is always of Id=0.
Then if I want to add a new note after removing the first note, I get an exception saying that the entity already exists. I concluded that the first entity with Id=0 has not been removed even though I called SubmitChanges on my data context.
Also, I'm using the same data context for data operations on my repository and on the same repository instance (a singleton for performance reasons).
To confirm that behavior, I tried to make the succession of calls and it failed !!!
this.DbContext.Notes.DeleteOnSubmit(value);
this.DbContext.SubmitChanges();
this.DbContext.Notes.InsertOnSubmit(value);
this.DbContext.SubmitChanges();
It says that it cannot add an Entity that already exists.
Any explanation for this behavior?
Thanks in advance.
Note :
When I use two different instances of the data context, this behavior disappears.
Well You answered your own question really at the end. Lets step through this:
You get the DbContext from the Database
Your Deleting an entry and submitting the Database(OK fine)
Now on this insertion your using an OLD instance of the database.
Everytime you make a
SubmitChanges();
You have update your reference, because its old.
So if you have a method that does multiple Transactions you NEED to refresh your local variable.
ONE instance of a Database should do ONE change

Entity Framework POCO long-term change tracking

I'm using .NET entity framework 4.1 with code-first approach to effectively solve the following problem, here simplified.
There's a database table with tens of thousands of entries.
Several users of my program need to be able to
View the (entire) table in a GridRow, which implied that the entire Table has to be downloaded.
Modify values of any random row, changes are frequent but need not be persisted immediately. It's expected that different users will modify different rows, but this is not always true. Some loss of changes is permitted, as users will most likely update same rows to same values.
On occasion add new rows.
Sounds simple enough. My initial approach was to use a long-running DbContext instance. This one DbContext was supposed to track changes to the entities, so that when SaveChanges() is called, most of the legwork is done automatically. However many have pointed out that this is not an optimal solution in the long run, notably here. I'm still not sure if I understand the reasons, and I don't see what a unit-of-work is in my scenario either. The user chooses herself when to persist changes, and let's say that client always wins for simplicity. It's also important to note that objects that have not been touched don't overwrite any data in the database.
Another approach would be to track changes manually or use objects that track changes for me, however I'm not too familiar with such techniques, and I would welcome a nudge in the right direction.
What's the correct way to solve this problem?
I understand that this question is a bit wishy-washy, but think of it as more fundamental. I lack fundamental understanding about how to solve this class of problems. It seems to me that long living DbContext is the right way, but knowledgeable people tell me otherwise, which leads me to confusion and imprecise questions.
EDIT1
Another point of confusion is the existance of Local property on the DbSet<> object. It invites me to use a long running context, as another user has posted here.
Problem with long running context is that it doesn't refresh data - I more discussed problems here. So if your user opens the list and modify data half an hour she doesn't know about changes. But in case of WPF if your business action is:
Open the list
Do as many actions as you want
Trigger saving changes
Then this whole is unit of work and you can use single context instance for that. If you have scenario where last edit wins you should not have problems with this until somebody else deletes record which current user edits. Additionally after saving or cancelling changes you should dispose current context and load data again - this will ensure that you really have fresh data for next unit of work.
Context offers some features to refresh data but it only refreshes data previously loaded (without relations) so for example new unsaved records will be still included.
Perhaps you can also read about MS Sync framework and local data cache.
Sounds to me like your users could have a copy (cached) of the data for an indefinate period of time. The longer the users are using cached data the greater the odds that they could become disconnected from the database connection in DbContext. My guess is EF doesn't handle this well and you probably want to deal with that. (e.g. occaisionally connected architecture). I would expect implementing that may solve many of your issues.

How does NHibernate determine whether to Insert or Update a record?

When using Session.SaveOrUpdate(myEntity); how does NHibernate decide how whether to insert a new record or update an existing one?
I am having trouble whilst saving one object in a S#arp project. It is retrieved from storage, then stored in session state for a couple of web requests, then saved back to the database with one property changed (not the S#arp [DomainSignature]).
I have, at runtime, compared the object that is about to be persisted with a freshly retrieved version straight from the database using the Equals() method and that returns true. However, the object still ends up creating a new row in the database.
Elsewhere in the application this is working fine but I am hoping for a pointer on how NHib is working this out.
Basically SaveOrUpdate() is looking for an identifier. If the identifier is present, it will update the record in the database. If the identifier is not present, it will create a new record.
However, it sounds like you might have something funky going on in your session. You might want to try SaveOrUpdateCopy() to see if this solves your issue.

Categories