I am trying to update an entity's FK. I am doing it like this:
myEntity.FK_ID= Guid.Parse("aff4b5d9-e197-4f0d-85ff-b04464d9e4f0"); //Entity with this Guid exists inside the DB
myEntity.ForeignKeyProperty= null;
Then I try to update the entity (new context) like this:
using (MyContext db = new MyContext ())
{
//db.Benutzer.Attach(entity); // <-- Same Exception
db.Entry(entity).State = EntityState.Modified;
}
This results in a InvalidOperationException:
A referential integrity constraint violation occurred: The property value(s) of 'MyTable.MyTable_ID' on one end of a relationship do not match the property value(s) of 'MyEntity.FK_ID' on the other end.
I really don't know why. I then tried the following:
I changed the value of FK_ID to the target value inside the Database. This worked (okay, EF chaching some stuff maybe...)
But then I rechanged the value to something else and it STILL works.
After the manual DB change it now works for this one entity EVERYTIME. If I try to update another entity I get the same Exception. Any ideas on why this is happening?!
Regards,
Marcel
EDIT:
Here's a more complete Code:
//In MVC-Controller
Benutzer dbBenutzer = Database.GetBenutzerByID(model.ID_Benutzer);
// ... Do some other changes to the entity
dbBenutzer.ChangeMitarbeiter = null;
dbBenutzer.MitarbeiterChange_ID = CurrentUser.Mitarbeiter_ID;
//...SaveChanges via
Database.Update<Benutzer>(dbBenutzer);
// In Repository
public static int Update<E>(E entity) where E : class
{
using (Context db = new MMVContext())
{
try
{
db.Entry(entity).State = EntityState.Modified; //EXCEPTION
return SaveRepositoryChanges<E>(db);
}
catch (Exception e)
{
Logging.Error(e.ToExtString());
return -1;
}
}
}
Related
I am trying to use Entity Framework for work with database, I use Extension Method and pass Entity Context Into Logic Codes, The Database is update successful, but when I call back, result, I still old Records, I guess that issue on Cache of Entities, But It not make clear, I could not find any thing wrong in my code. Please help:
Extension method:
public static bool UpdateTruck(this Truck Truck, Truck updateInfo, Entities entities)
{
var isSuccess = true;
try
{
// Find Enity Object
var ObjectModel = entities.Truck.Where(x => x.Code == Truck.Code && x.CodePlant == Truck.CodePlant).FirstOrDefault();
// Mapping Modified Properties
ObjectModel = Mapper.Map(updateInfo, ObjectModel);
// Create Database Entity Transaction
entities.Truck.AddOrUpdate(ObjectModel);
//Save Changes
entities.SaveChanges();
}
catch (Exception exception)
{
Debug.WriteLine("[Application Exception:] " + exception.Message);
isSuccess = false;
}
return isSuccess;
}
Here is where I call: if (truckInfo.FindTruck(entities).UpdateTruck(truckInfo,entities))
After that, i checked database, i value update success update, but when I call:
using (Entities entities = new Entities())
{
PageModel.Truck= Truck.FindTruck(entities);
....
It receive old record.
Entity Framework caches objects internally in a DbContext instance.
Look here
Your issue isn't caching. You are using the AddOrUpdate method, which is only designed for use when initialising a database with seed data.
Use:
entities.Truck.Attach(Truck); // if it already exists.
// since you are loading it again for some reason
var ObjectModel = entities.Truck.Where(x => x.Code == Truck.Code && x.CodePlant == Truck.CodePlant).FirstOrDefault();
// Mapping Modified Properties
ObjectModel = Mapper.Map(updateInfo, ObjectModel); // this looks dubious
// You've just loaded it from the context so it's tracked, so you could just save it
entities.SaveChanges();
Error message: Attaching an entity of type failed because another entity of the same type already has the same primary key value.
Question: How do I attached an entity in a similar fashion as demonstrated in the AttachActivity method in the code below?
I have to assume the "another entity" part of the error message above refers to an object that exists in memory but is out of scope (??). I note this because the Local property of the DBSet for the entity type I am trying to attach returns zero.
I am reasonably confident the entities do not exist in the context because I step through the code and watch the context as it is created. The entities are added in the few lines immediately following creation of the dbcontext.
Am testing for attached entities as specified here:what is the most reasonable way to find out if entity is attached to dbContext or not?
When looking at locals in the locals window of visual studio I see no entities of type Activity (regardless of ID) except the one I am trying to attach.
The code executes in this order: Try -> ModifyProject -> AttachActivity
Code fails in the AttachActivity at the commented line.
Note the code between the debug comments which will throw if any entities have been added to the context.
private string AttachActivity(Activity activity)
{
string errorMsg = ValidateActivity(activity); // has no code yet. No. It does not query db.
if(String.IsNullOrEmpty(errorMsg))
{
// debug
var state = db.Entry(activity).State; // Detached
int activityCount = db.Activities.Local.Count;
int projectCount = db.Activities.Local.Count;
if (activityCount > 0 || projectCount > 0)
throw new Exception("objects exist in dbcontext");
// end debug
if (activity.ID == 0)
db.Activities.Add(activity);
else
{
db.Activities.Attach(activity); // throws here
db.Entry(activity).State = System.Data.Entity.EntityState.Modified;
}
}
return errorMsg;
}
public int ModifyProject(Presentation.PresProject presProject, out int id, out string errorMsg)
{
// snip
foreach (PresActivity presActivity in presProject.Activities)
{
Activity a = presActivity.ToActivity(); // returns new Activity object
errorMsg = ValidateActivity(a); // has no code yet. No. It does not query db.
if (String.IsNullOrEmpty(errorMsg))
{
a.Project = project;
project.Activities.Add(a);
AttachActivity(a);
}
else
break;
}
if (string.IsNullOrEmpty(errorMsg))
{
if (project.ID == 0)
db.Projects.Add(project);
else
db.AttachAsModfied(project);
saveCount = db.SaveChanges();
id = project.ID;
}
return saveCount;
}
This is the class that news up the dbContext:
public void Try(Action<IServices> work)
{
using(IServices client = GetClient()) // dbContext is newd up here
{
try
{
work(client); // ModifyProject is called here
HangUp(client, false);
}
catch (CommunicationException e)
{
HangUp(client, true);
}
catch (TimeoutException e)
{
HangUp(client, true);
}
catch (Exception e)
{
HangUp(client, true);
throw;
}
}
I am not asking: How do I use AsNoTracking What difference does .AsNoTracking() make?
One solution to avoid receiving this error is using Find method. before attaching entity, query DbContext for desired entity, if entity exists in memory you get local entity otherwise entity will be retrieved from database.
private void AttachActivity(Activity activity)
{
var activityInDb = db.Activities.Find(activity.Id);
// Activity does not exist in database and it's new one
if(activityInDb == null)
{
db.Activities.Add(activity);
return;
}
// Activity already exist in database and modify it
db.Entry(activityInDb).CurrentValues.SetValues(activity);
db.Entry(activityInDb ).State = EntityState.Modified;
}
Attaching an entity of type 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.
The solution is that
if you had to use GetAll()
public virtual IEnumerable<T> GetAll()
{
return dbSet.ToList();
}
Change To
public virtual IEnumerable<T> GetAll()
{
return dbSet.AsNoTracking().ToList();
}
I resolved this error by changing Update method like below.
if you are using generic repository and Entity
_dbContext.Set<T>().AddOrUpdate(entityToBeUpdatedWithId);
or normal(non-generic) repository and entity , then
_dbContext.Set<TaskEntity>().AddOrUpdate(entityToBeUpdatedWithId);
If you use AddOrUpdate() method, please make sure you have added
System.Data.Entity.Migrations namespace.
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?
I wrote a function to handle views in mysql with entity data model. The column in the database is an int(10), but when I execute this block of code it gives me this error:
Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.
If I set the value to 5 manually and set hardcode to 5 into the code block, it doesn't fail on savechanges.
public static void AddPortfolioView(int id)
{
using (var db = new EyeMazingEnt())
{
var portfolio = (from a in db.portfolios where a.id.Equals(id) select a).SingleOrDefault();
if (portfolio != null)
{
portfolio.views = 0;
db.SaveChanges();
}
}
}
I have the following update function
public void UpdateBatchDefinition(BatchDefinition batchToUpdate)
{
if (batchToUpdate == null)
{
throw new ArgumentNullException("batchToUpdate");
}
BatchDefinition foundDefinition =
this.context.BatchDefinitions.SingleOrDefault(definition => definition.Id == batchToUpdate.Id);
if (foundDefinition != null)
{
if (!string.IsNullOrWhiteSpace(batchToUpdate.Name))
{
foundDefinition.Name = batchToUpdate.Name;
}
if (!string.IsNullOrWhiteSpace(batchToUpdate.Description))
{
foundDefinition.Description = batchToUpdate.Description;
}
if (!string.IsNullOrWhiteSpace(batchToUpdate.LoadType))
{
foundDefinition.LoadType = batchToUpdate.LoadType;
}
if (batchToUpdate.JobId != Guid.Empty)
{
foundDefinition.JobId = batchToUpdate.JobId;
}
foundDefinition.Tables = batchToUpdate.Tables;
this.context.SaveChanges();
}
}
the issue I am having Is when I am trying to update the Tables list. Tables is a List of Table and Table is a Entity of another table
Tables could be added to, removed from or left alone. I need to update that with what ever is being passed in
when I run this right now I get an 'EntityValidationErrors' error, though it wont tell me what the validation issue actually is.
on Inserting I got the same error but was able to fix it using the following
var underlyingContext = this.context as DbContext;
if (underlyingContext != null)
{
foreach (var table in batchDefinition.Tables)
{
// Need to mark the table entity as unchanged or
// else EF will treat it as a new table
underlyingContext.Entry(table).State = EntityState.Unchanged;
}
}
so I tried using that in this update function
var underlyingContext = this.context as DbContext;
if (underlyingContext != null)
{
foreach (var table in foundDefinition.Tables)
{
// Need to mark the table entity as unchanged or
//else EF will treat it as a new table
underlyingContext.Entry(table).State = EntityState.Unchanged;
}
}
foundDefinition.Tables = batchToUpdate.Tables;
and I get the following error instead:
AcceptChanges cannot continue because the object's key values conflict
with another object in the ObjectStateManager. Make sure that the key
values are unique before calling AcceptChanges.
Any thoughts one what I am missing here?
Change end of your update method like this:
foreach (var t in foundDefinition.Tables.ToList())
Context.Tables.Remove(t);
foundDefinition.Tables = batchToUpdate.Tables;
this.context.SaveChanges();
And about your last error, it is said that there are some duplicates in your context. So, EF can't save the context changes into the db (because there are duplicates in the context!)
In fact, I don't know the last error is from add or delete - you didn't mention clearly. So, I don't know the last two code samples are from your add method, or your update method...
However for update, the trick I mentioned here, must solve your problem for update...