Using Entity Framework Core 3.0 and facing an odd issue where EF will throw an exception if I try to update an entity with ID=0, it thinks that ID=0 is a temporary value. Same code updates entity with ID=1 or higher without any problems.
Exception:
InvalidOperationException: The property 'Id' on entity type 'MyType' has a temporary value
while attempting to change the entity's state to 'Modified'. Either
set a permanent value explicitly or ensure that the database is
configured to generate values for this property.
Exception is triggered on the following statement:
_context.Attach(MyType).State = EntityState.Modified;
I don't want to reseed all my tables to start with 1.
Is this expected behavior with EF? It should be possible to save entities with ID=0.
Any advice on how to resolve this?
Thanks.
You have to do something about this zero ID value. It's a ticking time bomb.
You'll always have to be on your guard because it definitely is expected behaviour. EF has inner logic depending on key default values. In EF6 you could do this because it was less refined. (In this area that is).
Let me show you how leaving this ID value can backfire on you in the future.
You have this MyType object. Let's call it entity to follow some naming conventions/habits. Its ID value is 0 and it's not attached to the context.
Now suppose you don't use this rather redundant way to attach it as modified but the new EF-core way:
context.Update(entity);
Now you won't see any exception, but no, the issue isn't fixed. It's gotten worse. The entity object's state is Added now and you're going to add a new record to your table. That might even go unnoticed for a while, adding to the pile of mess you have to clean up later.
Had its ID value been > 0, EF's Update method would have concluded it's an existing entity and its state should be Modified.
You can set entity's state to Modified if (1) it's not attached and (2) you use...
context.Entry(entity).State = EntityState.Modified;
And that's another time bomb. Later code changes remove the first condition (it's not attached) and boom.
Related
I get the error "Cannot insert explicit value for identity column in table 'UserPermission' when IDENTITY_INSERT is set to OFF" trying to insert a record as follows:
dbContext.User.Add(someUser);
dbContext.SaveChanges();
That being said, the User file has the custom class UserPermission as one of its parameters, and someUser's UserPermission is not null and has a set ID parameter. Why does this happen and is it possible to avoid getting this error without having to explicitly add a UserPermissionID foreign key parameter in my User model and setting the UserPermission parameter to null?
Thanks in advance.
This issue typically happens when deserializing entities that have related entities in the object graph then attempting to add them. UserPermission is likely an existing record that in the DB is set up with an identity PK, but EF doesn't appear to recognize that in the entity definition. (I.e. set to DatabaseGenerated(DatabaseGeneratedOption.Identity). If it had been you would most likely be seeing a different problem where a completely new duplicate UserPermission was being created.
If someUser, and it's associated someUser.UserPermission are deserialized entities then you need to do a bit of work to ensure EF is aware that UserPermission is an existing row:
void AddUser(User someUser)
{
var existingPermission = _context.UserPermissions.Local
.SingleOrDefault(x => x.UserPermissionId == someUser.UserPermission.UserPermissionId);
if (existingPermission != null)
someUser.UserPermission = existingPermission;
else
_context.Attach(someUser.UserPermission);
_context.Users.Add(someUser);
_context.SaveChanges();
}
In a nutshell, when working with detached entities that a DbContext may not be tracking, we need to check the Local state for any existing tracked instance for that ID. If we find one, we substitute the detached reference for the tracked one. If we don't find one, we attach the detached one before Adding our user.
This still isn't entirely safe because it assumes that the referenced UserPermission will exist in the database. If for any reason a non-existent UserPermission is sent in (row deleted, or fake data) you will get an exception on Save.
Passing detached entity references around can seem like a simple option at first, but you need to do this for every reference within a detached entity. If you simply call Attach without first checking, it will likely work until you come across a scenario where at runtime it doesn't work because the context happens to already be tracking an instance.
I'm using the code show below to update an entity model. But I get this error:
Store update, insert, or delete statement affected an unexpected number of rows (0)
And reason of this error is also known, it's because the property does not exist in the database. For that I found have only one option: first check that the entity exists, then update it.
But, as I'm updating 10,000+ rows at a time, it will be time consuming to check each time in database if this property exist or not.
Is there any another way to solve this ?
Thank you.
foreach (Property item in listProperties)
{
db.Properties.Attach(item);
db.Entry(item).Property(x => x.pState).IsModified = true;
}
db.SaveChanges();
You use it the wrong way. If you want to update without retrieving the entity, just change the state of the updated entity with providing the id.
foreach (Property item in listProperties)
{
db.Entry(item).State = EntityState.Modified;
}
db.SaveChanges();
Attaching an existing but modified entity to the context
If you have an entity that you know already exists in the database but
to which changes may have been made then you can tell the context to
attach the entity and set its state to Modified.
When you change the state to Modified all the properties of the entity
will be marked as modified and all the property values will be sent to
the database when SaveChanges is called.
Source
I got this error Just by updating EF version from 5 to 6 solved the issue.
I have table A and B
A like : id
name
bid
B like : id
type
in table A has a data record reference with B1,now I want update A reference with B2.
in my unitofwork if I set AutoDetectChangesEnabled = true it's work ok, but I set AutoDetectChangesEnabled = false reason is I want to up speed throw the exception like this:
The changes to the database were committed successfully, but an error occurred while updating the object context. The ObjectContext might be in an inconsistent state. Inner exception message: A referential integrity constraint violation occurred: The property value(s) of 'GoodsKind.goods_kind_id' on one end of a relationship do not match the property value(s) of 'EnrolmentType.goods_kind' on the other end."
how cand i do?
I just had this error as well. The problem for me was that I have a complex type. When I changed the master record (let's say Person) I also wanted to change the complex type List with his contact information(s). So when I tried to save them both in one screen I got this error. Check if you fill all the ids on your screen for the master record and the complex type records. Check if they are posted to the server (if you use in example MVC). You can do this by checking the Bind statement by your MVC action.
The error says that the ID and the object specified doesn't match. This means that you are saying that A has a B with ID=2 but at the same time you have A with an object of type B with ID=5. Because you are working in a disconnected environment, EF doesn't know which one is the correct. To solve this issue you can do one of the following things:
-Get the object from EF, modify it and then save (connected environment).
OR
-Update the IDs manually (update A setting ID=5 because the object B has ID=5).
Always remember that EF tracks changes if it is in a connected environment and the tracking is enabled. If not, it has no clue of the changes you made until it tries to save it in the DB (where the object is compared with the values in the DB). One thing that you can do to manually tell EF that the entity has been modified in a disconnected environment is:
dbContext.Entry(objectA).State = EntityState.Modified;
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;
My object which I am going to insert has a parent object as a navigational property.
When I "add" the object to insert it, it also set the ObjectStateManager of my parent object (which is already inserted) to Added and try to insert it. I've verified it in SQL Profiler and thus raises the exception of unique key violation.
I am getting rid of this in two ways
Before adding the object I set all the navigational properties to null
Set the ObjectStateManager of parent object to Modified.
But this seems more like hack than a solution. I believe Entity Framework must have some elegant solution to this.
Kindly suggest.
The second approach is correct solution for this problem. When you call AddObject EF will attach all entities from the object graph in Added state. If you also have existing entities in the graph you must tell EF about them by either setting their state to Unchanged or Modified.