How can I ensure that EF 6 retrieves the changes to a record that are made after a trigger executes?
My issue is that I have a trigger on my table that generates column values after insert. When I add my new object and call SaveChanges(), I want to turn around and get that object back out with the updated values. I've found some similar questions here, but they are old and suggest using things like context.Refresh() that do not exist now. In one case there was a suggestion to use:
context.Configuration.AutoDetectChangesEnabled = true;
This hasn't helped either.
Thanks for your help!
Related
I have some Hibernate code running against a Postgres 9.5 DB, which looks like roughly like below (anonymized) -
Integer myEntityId = myEntity.getId();
getCurrentSession().evict(myEntity);
myEntity.setId(null);
MyEntity clonedMyEntity = (MyEntity)getCurrentSession().merge(myEntity);
myEntity.setMyBooleanField(false);
getCurrentSession().save(myEntity);
I have an entity myEntity with a large number of fields. I want to create a duplicate of the record with only 1 field value changed. To achieve this, I evict the entity from session, set Primary Key to null, merge it back to session, set the field I want to change, and then save the entity to DB. However, this code (which was working correctly for some time), is not working now. It sees incorrect value for the boolean field I am trying to modify - as a result violating some database constraints. Please help me fix this or suggest a better way to achieve what I am trying.
The error was happening not on adding this record but on add of another record to an audit table, triggered by the addition of this record. A coworker suggested me to use Eclipse Breakpoint view and use the add breakpoint option there and select the ConstraintViolationException class - this helped me to see the error for which trigger was failing and why and accordingly modify the data to suit the database constraint.
I was trying to manually implement a cascade delete in my ASP.NET Core website.
So, I got a Poll section which is based on 3 entities: PollQuestion, PollOption, PollAnswer.
I'm starting this by deleting all the answers, and this goes fine, then I move to deleting the options with this code:
if (answersDeleted) {
options = GetOptionsList(_pollID);
context.PollOption.RemoveRange(options);
context.SaveChanges();
return true;
} else {
return false;
}
When the SaveChanges() is executed I get this exception:
Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: Database operation expected to affect 1 row(s) but actually affected 2 row(s). Data may have been modified or deleted since entities were loaded.
So. I can't really understand why he was expecting to affect 1 row since I pass a list to RemoveRange().
In case someone could make use of this one day.... i found the problem, it wasn't strictly related to the chunk of code i posted; few days ago i modified the poll table, and changed the Key, from a single field key to a composite key, then i forgot to reflect that change in my Model, which still was using a single key. It wasn't returning any error so i didn't notice this until i had to do other stuff on the DB and there i found the problem.
I am trying to delete a record if it exists using Entity Framework - I want to generate something like
delete from tbl where id = 1
I don't care whether any records exist, I just want to delete them if they do. I should be able to do with without selecting them first like this:
var record = new tbl { id = 1, rel = new tbl_related { tbl_id = 1 } };
context.tbl.Attach(tbl);
context.tbl.Remove(tbl);
context.SaveChanges();
The syntax might not exactly be there because this isn't a copy and paste, and I've added the foreign key relationship to show that I'm taking this into account.
On running this code the correct SQL is generated by EF and run but I get a System.Data.Entity.Infrastructure.DbUpdateConcurrencyException saying "Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded".
However, I'm fully expecting zero rows to be deleted a lot of the time. Any ideas on how I can get around this?
I've been pointed to How to ignore a DbUpdateConcurrencyException when deleting an entity as a possible duplicate. This suggests handling the DbUpdateConcurrencyException which I am now doing (and ignoring), but that post talks about trying to delete rows that might have been deleted - I want to delete rows that might never have existed. I know this might just be a question of semantics because the resolution is the same but I want to highlight that I am doing something that I see as perfectly reasonable and the Framework is not handling it very well.
Thanks
There is an extension for EF on github that allows you to update and delete entities with a single call to the database.
With this extension you can do something like this:
context.tbl.Delete(t => t.Id == 1);
A single call should eliminate your DbUpdateConcurrencyException.
None of the many questions on this topic seem to match my situation. I have a large data model. In certain cases, only a few of the fields need be displayed on the UI, so for those I replaced the LINQ to Entity query that pulls in everything with an Entity SQL query retrieving only the columns needed, using a Type constructor so that I got an entity returned and not a DbDataRecord, like this:
SELECT VALUE MyModelNameSpace.INCIDENT(incident.FieldA, incident.FieldB, ...) FROM ... AS ...
This works and displays the fields in the UI. And if I make a change, the change makes it back to the entity model when I tab out of the UI element. But when I do a SaveChanges, the changes do not get persisted to the database. No errors show up in the Log. Now if I very carefully replace the above query with an Entity Sql query that retrieves the entire entity, like this:
SELECT VALUE incident FROM MyDB.INCIDENTs AS incident...
Changes do get persisted in the database! So as a test, I created another query like the first that named every column in the entity, which should be the exact equivalent of the second Entity SQL query. Yet it did not persist changes to the database either.
I've tried setting the MergeOption on the returned result to PreserveChanges, to start tracking, like this:
incidents.MergeOption = MergeOption.PreserveChanges;
But that has no effect. But really, if retrieving the entire entity with Entity Sql persists changes, what logical purpose would there be for behaving differently when a subset of the fields are retrieved? I'm wondering if this is a bug?
Gert was correct, the problem was that the entity was not attached. Dank U wel, Gert! Ik was ervan verbluft!
I just wanted to add a little detail to show the full solution. Basically, the ObjectContext has an Attach method, so you'd think that would be it. However, when your Entity SQL select statement names columns, and you create the object using a Type as I did, the EntityKey is not created, and ObjectContext.Attach fails. After trying and failing to insert the EntityKey I created myself, I stumbled across ObjectSet.Attach, added in Entity Framework 4. Instead of failing, it creates the EntityKey if it is missing. Nice touch.
The code was (this can probably be done in fewer steps, but I know this works):
var QueryString = "SELECT VALUE RunTimeUIDesigner.INCIDENT (incident.INCIDENT_NBR,incident.LOCATION,etc"
ObjectQuery<INCIDENT> incidents = orbcadDB.CreateQuery<INCIDENT>(QueryString);
incidents.MergeOption = MergeOption.PreserveChanges;
List<INCIDENT> retrievedIncidents = incidents.ToList<INCIDENT>();
orbcadDB.INCIDENTs.Attach(retrievedIncidents[0]);
iNCIDENTsViewSource.Source = retrievedIncidents;
I have a SalesOrder table with columns for ID and OrderID. ID is an auto-generated int. OrderID is a non-nullable string with a max length of 20, and we use it to store the customer's order number for reference.
After adding my new SalesOrder and calling SaveChanges, I get the following error:
Cannot insert the value NULL into column 'OrderID', table 'SalesOrder'; column does not allow nulls. INSERT fails.
The statement has been terminated.
Problem is, the object that I'm saving actually does have an OrderID! It's almost like it's trying to save the entity first before it saves all the values. Is this how EF handles things?
My setup is EF4.1, using an EDMX model-first approach. StoreGeneratedPattern is set to None. Default Value is currently set to (None) but I've tried various values. Entity Key is False, since it's not part of the key. I've also tried deleting the SalesOrder entity and regenerating it from the database.
I would also like to see your code...I had similar problems when filling objects in a loop then saving them with savechanges. I thought all the fields were populated, but they were not.
I'd have to see your code that executes before the save changes before I can offer anything really helpful.
If your problem is like mine and you are calling savechanges after using an iterator to populate your objects, then you can find the bad data by moving savechanges into the iterator so that it is called with each iteration...but this is all hypothetical guesswork without seeing your code...