I am trying to get the last inserted Id from database via Entity Framework, however my problem is somehow unique and I am not able to find any solution, but to rewrite my whole infrastructure and business layer, so all my Ids are Guids, which I am able to create manually, or get last record with another database call after commit.
Here is the problem. I have a three-layered architecture, where I am using UoW, repository, services and facades. I will show my code from top to bottom, so you can understand.
Here is my facade, where uow.Commit is calling SaveChanges()
public async Task<int> RegisterUserAsync(UserCreateDto user)
{
using (var uow = UnitOfWorkProvider.Create())
{
var id = _userService.Create(user);
await uow.Commit();
return id;
}
}
As you can see I am sending only my DTO into the service, where I process is like this, also I am mapping inside service
public virtual int Create(TCreateDto entityDto)
{
var entity = Mapper.Map<TEntity>(entityDto);
Repository.Create(entity);
return entity.Id;
}
and finally my repository looks like this
public TKey Create(TEntity entity)
{
Context.Set<TEntity>().Add(entity);
return entity.Id;
}
Is there some elegant solution to this? Like I said my only idea is to switch all Ids to Guid or second call for Id after commit, which I find as not very good solution, because when I want to connect two or more tables in one transaction it would be impossible.
EF Core solution of the problem is simple - auto generated PK of an entity instance is available after calling SaveChanges[Async]. e.g.
var entity = Mapper.Map<TEntity>(entityDto);
Context.Add(entity);
// Here entity.Id contains auto-generated temporary value
// Other stuff...
Context.SaveChanges();
// Here entity.Id contains actual auto-generated value from the db
So the problem is more in the design of your infrastructure - all these (unnecessary) UoW, repository, services and facades simply hide that functionality.
The only relatively simple and elegant solution I see with your architecture is to change the service return type from int to Func<int>, e.g.
public virtual Func<int> Create(TCreateDto entityDto)
{
var entity = Mapper.Map<TEntity>(entityDto);
Repository.Create(entity);
return () => entity.Id; // <--
}
Then in your façade you could use
public async Task<int> RegisterUserAsync(UserCreateDto user)
{
using (var uow = UnitOfWorkProvider.Create())
{
var id = _userService.Create(user);
await uow.Commit();
return id(); // <-- the actual id!
}
}
Edit:
Actually EF Core provides another option which would allow you to keep your current design intact - the HiLo key generation strategy, but only if the database provider supports it. I can say for sure Microsoft.EntityFrameworkCore.SqlServer and Npgsql.EntityFrameworkCore.PostgreSQL do support it with respectively ForSqlServerUseSequenceHiLo and ForNpgsqlUseSequenceHiLo fluent APIs.
I'm using Entity Framework 6 (using generated models and DbContext) for my project. The architecture I'm using in my program is that the data access layer is abstracted from the application. This means my entities will mostly stay in detached state.
It seems that reattaching any previously connected entities seems impossible (or I'm not doing it properly).
I've tested a case in isolation and was able to narrow the problem down. Here are the steps.
Get the entity from the context and dispose the context. This detaches the entity.
public async Task<ArchiveEntry> GetEntry(string api, string id)
{
// Omitted some code for simplicity
ArchiveEntry entry;
using (var db = new TwinTailDb())
{
entry = await db.ArchiveEntries.Where(a => a.Id == id).SingleOrDefaultAsync();
}
return entry;
}
Save the entity regardless if it was changed or not.
public async Task Save()
{
// Omitted some code for simplicity
using (var db = new TwinTailDb())
{
db.ArchiveEntries.AddOrUpdate(a => a.Id, this);
await db.SaveChangesAsync();
}
}
Finally, reattach the detached entity.
public async Task RevertChanges()
{
using (var db = new TwinTailDb())
{
if (db.Entry(this).State == EntityState.Detached && Id != 0)
{
db.ArchiveEntries.Attach(this);
//await db.Entry(this).ReloadAsync(); // Commented since this is irrelevant
}
}
}
Then I run this function to use the code above.
public async Task Test()
{
ArchiveEntry entry = await ArchiveService.GetEntry(null, "7");
await entry.Save();
await entry.RevertChanges();
}
Then it throws this error:
Attaching an entity of type 'TwinTail.Entities.ArchiveEntry' 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 entities to 'Unchanged' or 'Modified' as appropriate.
Here's an important point. If I skip step 2, it doesn't throw an exception.
My speculation is that the entity was modified and saved in a different context. If step 2 was skipped, the entity remains unchanged so reattaching it doesn't pose a problem (just guessing). However, this entity is already in a detached state so this should be irrelevant.
Another point, the ChangeTracker doesn't contain anything during these steps. Also, if I perform any context operation on the detached entity, it throws an exception saying that it should be attached first. I've also noticed that the internal _entitywrapper still has a reference to the old context.
So, finally, here's the question. How do I properly reattach an entity and why does this exception happen.
I've asked something similar in a different question (How to revert changes on detached entities) but felt that I need to post a new one since this is more general.
The architecture I'm using in my program is that the data access layer is abstracted from the application.
It looks like you are implementing these methods on the ArchiveEntry class itself. That is not an abstracted data access layer, and passing entities around to many short-lived contexts like this will get you into trouble.
Instead of giving the entity classes their own methods for managing persistence concerns, you should put that code into a class separate from the entity, and make sure that once an entity gets attached to a context, you keep using that same context until it gets disposed. Once the context is disposed, if you want to do another operation on the entity, you should retrieve it from a new context before trying to do any (attached) things with it.
I was using AsNoTracking() so, the exception was odd to me. The code below fixed the issue in my code. I think I could get ride of the code in the try block and only use the catch block, but I never tested the concept.
Entity Base class with PrimaryKey
public class EntityBase<K>
{
[NotMapped]
public virtual K PrimaryKey {get;}
}
Update function
public static void Update<T,K>(DbContext context, T t) where T:EntityBase<K>
{
DbSet<T> set = context.Set<T>();
if(set==null) return;
if(context.Entry<T>(t).State == EntityState.Detached)
{
try
{
T attached = set.Attached(t);
context.Entry<T>(attached).State = EntityState.Modified;
}catch(Exception ex)
{
T found = set.Find(t.PrimaryKey);
context.Entry(found).CurrentValues.SetValues(t);
}
}
context.SaveChanges();
}
Extension Function
public static void Update<T,K>(this DbContext context, T t) where T:EntityBase<K> => Update<T,K>(context, t);
So I'm new to EF (I'm using EF6) and I have problem understanding the concept, I'm trying to update entity with child collection.
Here's my entity class :
public class TimeSheet
{
public int TimeSheetID { get; set; }
public virtual ICollection<TimeSheetDetail> Details { get; set; }
}
public class TimeSheetDetail
{
public int TimeSheetDetailID { get; set; }
public int TimeSheetID { get; set; }
public virtual TimeSheet TimeSheet { get; set; }
}
My update method :
public void Update(TimeSheet obj)
{
var objFromDB = Get(obj.TimeSheetID);
var deletedDetails = objFromDB.Details.Except(obj.Details).ToList();
_dbContext.Entry(obj).State = EntityState.Modified;
//track if details exist
foreach (var details in obj.Details)
{
_dbContext.Entry(details).State = details.TimeSheetDetailID == 0 ? EntityState.Added : EntityState.Modified;
}
//track deleted item
foreach (var deleted in deletedDetails)
{
_dbContext.Entry(deleted).State = EntityState.Deleted;
}
}
public TimeSheet Get(object id)
{
//return _timeSheet.Find(id); //Without AsNoTracking I got error
int x = Convert.ToInt32(id);
return _timeSheet.AsNoTracking().SingleOrDefault(a => a.TimeSheetID == x);
}
Above code give me Attaching an entity of type 'ClassName' failed because another entity of the same type already has the same primary key value. So my quesstion is :
How do you update child collection with EF? Means that I need to Add new if it doesn't exist in DB, update otherwise, or delete from DB if it is removed in the POST.
If I don't use AsNoTracking(), it will throw Saving or accepting changes failed because more than one entity of type 'ClassName' have the same primary key value. I notice that the error was cause by my DbSet add the data from DB to its Local property if I don't use AsNoTracking() which cause the EF framework to throw the error because it thinks I have a duplicate data. How does this work actually?
As you can see I'm trying to compare objFromDb against obj to check if user remove one of the details so I can remove it from the database. Instead I got bunch of DynamicProxies from the collection result. What is DynamicProxies and how does it work?
Is there any good article or 101 tutorial on EF? So far I've only see a simple one which doesn't help my case and I've looking around and find a mixed answer how to do stuff. To be honest, at this point I wish I would just go with classic ADO.Net instead of EF.
For a better understanding of the entity framework, think of the DbContext as proxy between your application and the database.
The DbContext will cache everything and will use every bit of data from the cached values unless you tell it not to do so.
For 1.: This depends on your environment if your DbContext is not disposed between selecting and updating the entites you can simply just call SaveChanges and your data will be saved. If your DbContext is disposed you can detach the entites from the context, change the data, reattach them and set the EntityState to modified.
I can't give you a 100% sure answer, because I stopped using the entity framework about half a year ago. But I know it is a pain to update complex relations.
For 2.: The command AsNoTracking tells the EF not to track the changes made to the entities inside this query. For example your select 5 TimeSheets from your Database, change some values in the first entity and delete the last one. The DbContext knows that the first entity is changed and the last one is deleted, if you call SaveChanges the DbContext will automatically update the first entity , delete the last one and leave the other ones untouched. Now you try to update an entity by yourself and attach the first entity again to the DbContext.
The DbContext will now have two entites with the same key and this leads to your exception.
For 3.: The DynamicProxies is the object that the entity framework uses to track the changes of these entities.
For 4.: Check this link, also there is a good book about entity framework 6 (Title: "Programming Entity Framework")
I've got an aggregate for a specific type of entity which is stored in a collection inside the aggregate. Now I'd like to add a new entry of that type and update the aggregate afterwards, however Entity Framework never updates anything!
Model
public class MyAggregate {
protected ICollection<MyEntity> AggregateStorage { get; set; }
public void AddEntity(MyEntity entity) {
// some validation
AggregateStorage.Add(entity);
}
}
API Controller
[UnitOfWork, HttpPost]
public void UpdateMyEntity(int aggregateId, MyEntityDto dto) {
var aggregate = _aggregateRepository.Find(aggregateId);
aggregate.AddEntity(...// some mapping of the dto).
_aggregateRepository.Update(aggregate);
}
EF Update
EntitySet.Attach(aggregate);
Context.Entry(aggregate).State = EntityState.Modified;
(Please note that there's an unit of work interceptor on the API action who fires DbContext.SaveChanges() after successful execution of the method.)
Funny thing is, the update never get's executed by EF. I've added a log interceptor to the DbContext to see what's going on sql-wise and while everything else works fine, an update statement never occurs.
According to this answer in detached scenario (either aggregate is not loaded by EF or it is loaded by different context instance) you must attach the aggregate to context instance and tell it exactly what did you changed, set state for every entity and independent association in object graph.
You must either use eager loading and load all data together at the beginning and
instead of changing the state of aggregate, change the state of entities:
foreach(var entity in aggregate.AggregateStorage)
{
if(entity.Id == 0)
Context.Entry(entity).State = EntityState.Added;
}
In a nutshell the exception is thrown during POSTing wrapper model and changing the state of one entry to 'Modified'. Before changing the state, the state is set to 'Detached' but calling Attach() does throw the same error. I'm using EF6.
Please find my code below(model names have been changed to make it easier to read)
Model
// Wrapper classes
public class AViewModel
{
public A a { get; set; }
public List<B> b { get; set; }
public C c { get; set; }
}
Controller
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
if (!canUserAccessA(id.Value))
return new HttpStatusCodeResult(HttpStatusCode.Forbidden);
var aViewModel = new AViewModel();
aViewModel.A = db.As.Find(id);
if (aViewModel.Receipt == null)
{
return HttpNotFound();
}
aViewModel.b = db.Bs.Where(x => x.aID == id.Value).ToList();
aViewModel.Vendor = db.Cs.Where(x => x.cID == aViewModel.a.cID).FirstOrDefault();
return View(aViewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(AViewModel aViewModel)
{
if (!canUserAccessA(aViewModel.a.aID) || aViewModel.a.UserID != WebSecurity.GetUserId(User.Identity.Name))
return new HttpStatusCodeResult(HttpStatusCode.Forbidden);
if (ModelState.IsValid)
{
db.Entry(aViewModel.a).State = EntityState.Modified; //THIS IS WHERE THE ERROR IS BEING THROWN
db.SaveChanges();
return RedirectToAction("Index");
}
return View(aViewModel);
}
As shown above line
db.Entry(aViewModel.a).State = EntityState.Modified;
throws exception:
Attaching an entity of type 'A' 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 entities to 'Unchanged' or 'Modified' as
appropriate.
Does anybody see anything wrong in my code or understand in what circumstances it would throw such error during editing a model?
Problem SOLVED!
Attach method could potentially help somebody but it wouldn't help in this situation as the document was already being tracked while being loaded in Edit GET controller function. Attach would throw exactly the same error.
The issue I encounter here was caused by function canUserAccessA() which loads the A entity before updating the state of object a. This was screwing up the tracked entity and it was changing state of a object to Detached.
The solution was to amend canUserAccessA() so that the object I was loading wouldn't be tracked. Function AsNoTracking() should be called while querying the context.
// User -> Receipt validation
private bool canUserAccessA(int aID)
{
int userID = WebSecurity.GetUserId(User.Identity.Name);
int aFound = db.Model.AsNoTracking().Where(x => x.aID == aID && x.UserID==userID).Count();
return (aFound > 0); //if aFound > 0, then return true, else return false.
}
For some reason I couldnt use .Find(aID) with AsNoTracking() but it doesn't really matter as I could achieve the same by changing the query.
Hope this will help anybody with similar problem!
Interestingly:
_dbContext.Set<T>().AddOrUpdate(entityToBeUpdatedWithId);
Or if you still is not generic:
_dbContext.Set<UserEntity>().AddOrUpdate(entityToBeUpdatedWithId);
seems to solved my problem smoothly.
It seems that entity you are trying to modify is not being tracked correctly and therefore is not recognized as edited, but added instead.
Instead of directly setting state, try to do the following:
//db.Entry(aViewModel.a).State = EntityState.Modified;
db.As.Attach(aViewModel.a);
db.SaveChanges();
Also, I would like to warn you that your code contains potential security vulnerability. If you are using entity directly in your view model, then you risk that somebody could modify contents of entity by adding correctly named fields in submitted form. For example, if user added input box with name "A.FirstName" and the entity contained such field, then the value would be bound to viewmodel and saved to database even if the user would not be allowed to change that in normal operation of application.
Update:
To get over security vulnerability mentioned previously, you should never expose your domain model as your viewmodel but use separate viewmodel instead. Then your action would receive viewmodel which you could map back to domain model using some mapping tool like AutoMapper. This would keep you safe from user modifying sensitive data.
Here is extended explanation:
http://www.stevefenton.co.uk/Content/Blog/Date/201303/Blog/Why-You-Never-Expose-Your-Domain-Model-As-Your-MVC-Model/
Try this:
var local = yourDbContext.Set<YourModel>()
.Local
.FirstOrDefault(f => f.Id == yourModel.Id);
if (local != null)
{
yourDbContext.Entry(local).State = EntityState.Detached;
}
yourDbContext.Entry(applicationModel).State = EntityState.Modified;
for me the local copy was the source of the problem.
this solved it
var local = context.Set<Contact>().Local.FirstOrDefault(c => c.ContactId == contact.ContactId);
if (local != null)
{
context.Entry(local).State = EntityState.Detached;
}
My case was that I did not have direct access to EF context from my MVC app.
So if you are using some kind of repository for entity persistence it could be appropiate to simply detach explicitly loaded entity and then set binded EntityState to Modified.
Sample (abstract) code:
MVC
public ActionResult(A a)
{
A aa = repo.Find(...);
// some logic
repo.Detach(aa);
repo.Update(a);
}
Repository
void Update(A a)
{
context.Entry(a).EntityState = EntityState.Modified;
context.SaveChanges();
}
void Detach(A a)
{
context.Entry(a).EntityState = EntityState.Detached;
}
Use AsNoTracking() where you are getting your query.
var result = dbcontext.YourModel.AsNoTracking().Where(x => x.aID == aID && x.UserID==userID).Count();
I have added this answer only because the problem is explained based on more complex data pattern and I found it hard to understand here.
I created a fairly simple application. This error occurred inside Edit POST action. The action accepted ViewModel as an input parameter. The reason for using the ViewModel was to make some calculation before the record was saved.
Once the action passed through validation such as if(ModelState.IsValid), my wrongdoing was to project values from ViewModel into a completely new instance of Entity. I thought I'd have to create a new instance to store updated data and then saved such instance.
What I had realised later was that I had to read the record from database:
Student student = db.Students.Find(s => s.StudentID == ViewModel.StudentID);
and updated this object. Everything works now.
I thought I'd share my experience on this one, even though I feel a bit silly for not realising sooner.
I am using the repository pattern with the repo instances injected into my controllers. The concrete repositories instantiate my ModelContext (DbContext) which lasts the lifetime of the repository, which is IDisposable and disposed by the controller.
The issue for me was that I have a modified stamp and row version on my entities, so I was getting them first in order to compare with the inbound headers. Of course, this loaded and tracked the entity that was subsequently being updated.
The fix was simply to change the repository from newing-up a context once in the constructor to having the following methods:
private DbContext GetDbContext()
{
return this.GetDbContext(false);
}
protected virtual DbContext GetDbContext(bool canUseCachedContext)
{
if (_dbContext != null)
{
if (canUseCachedContext)
{
return _dbContext;
}
else
{
_dbContext.Dispose();
}
}
_dbContext = new ModelContext();
return _dbContext;
}
#region IDisposable Members
public void Dispose()
{
this.Dispose(true);
}
protected virtual void Dispose(bool isDisposing)
{
if (!_isDisposed)
{
if (isDisposing)
{
// Clear down managed resources.
if (_dbContext != null)
_dbContext.Dispose();
}
_isDisposed = true;
}
}
#endregion
This allows the repository methods to re-new their context instance upon each use by calling GetDbContext, or use a previous instance if they so desire by specifying true.
I had this problem with local var and i just detach it like this:
if (ModelState.IsValid)
{
var old = db.Channel.Find(channel.Id);
if (Request.Files.Count > 0)
{
HttpPostedFileBase objFiles = Request.Files[0];
using (var binaryReader = new BinaryReader(objFiles.InputStream))
{
channel.GateImage = binaryReader.ReadBytes(objFiles.ContentLength);
}
}
else
channel.GateImage = old.GateImage;
var cat = db.Category.Find(CatID);
if (cat != null)
channel.Category = cat;
db.Entry(old).State = EntityState.Detached; // just added this line
db.Entry(channel).State = EntityState.Modified;
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
return View(channel);
Problem causes of loaded objects with same Key, so first we will detach that object and do the the updating to avoid conflict between two object with the same Key
i mange to fix the issue by updating state. when you trigger find or any other query operation on the same record sate has been updated with modified so we need to set status to Detached then you can fire your update change
ActivityEntity activity = new ActivityEntity();
activity.name="vv";
activity.ID = 22 ; //sample id
var savedActivity = context.Activities.Find(22);
if (savedActivity!=null)
{
context.Entry(savedActivity).State = EntityState.Detached;
context.SaveChanges();
activity.age= savedActivity.age;
activity.marks= savedActivity.marks;
context.Entry(activity).State = EntityState.Modified;
context.SaveChanges();
return activity.ID;
}
I had a similar issue, after probing for 2-3 days found ".AsNoTracking" should be removed as EF doesn't track the changes and assumes there are no changes unless an object is attached. Also if we don't use .AsNoTracking, EF automatically knows which object to save/update so there is no need to use Attach/Added.
I encountered this error where
two methods, A & B, in a single controller both used the same instance of an ApplicationDbContext, and
method A called method B
private ApplicationDbContext db;
// api methods
public JsonResult methodA(string id){
Resource resource = db.Resources.Find(id);
db.Entry(resource).State = EntityState.Modified;
db.SaveChanges();
return methodB()
}
public JsonResult methodB(string id){
Resource resource = db.Resources.Find(id);
db.Entry(resource).State = EntityState.Modified;
db.SaveChanges();
return new JsonResult();
}
I changed method B to have a using statement and rely only on the local db2.
After:
private ApplicationDbContext db;
// api methods
public JsonResult methodA(string id){
Resource resource = db.Resources.Find(id);
db.Entry(resource).State = EntityState.Modified;
db.SaveChanges();
return methodB()
}
public JsonResult methodB(string id){
using (var db2 = new ApplicationDbContext())
{
Resource resource = db2.Resources.Find(id);
db2.Entry(resource).State = EntityState.Modified;
db2.SaveChanges();
}
return new JsonResult();
}
Similar to what Luke Puplett is saying, the problem can be caused by not properly disposing or creating your context.
In my case, I had a class which accepted a context called ContextService:
public class ContextService : IDisposable
{
private Context _context;
public void Dispose()
{
_context.Dispose();
}
public ContextService(Context context)
{
_context = context;
}
//... do stuff with the context
My context service had a function which updates an entity using an instantiated entity object:
public void UpdateEntity(MyEntity myEntity, ICollection<int> ids)
{
var item = _context.Entry(myEntity);
item.State = EntityState.Modified;
item.Collection(x => x.RelatedEntities).Load();
myEntity.RelatedEntities.Clear();
foreach (var id in ids)
{
myEntity.RelatedEntities.Add(_context.RelatedEntities.Find(id));
}
_context.SaveChanges();
}
All of this was fine, my controller where I initialized the service was the problem. My controller originally looked like this:
private static NotificationService _service =
new NotificationService(new NotificationContext());
public void Dispose()
{
}
I changed it to this and the error went away:
private static NotificationService _service;
public TemplateController()
{
_service = new NotificationService(new NotificationContext());
}
public void Dispose()
{
_service.Dispose();
}
Here what I did in the similar case.
That sitatuation means that same entity has already been existed in the context.So following can help
First check from ChangeTracker if the entity is in the context
var trackedEntries=GetContext().ChangeTracker.Entries<YourEntityType>().ToList();
var isAlreadyTracked =
trackedEntries.Any(trackedItem => trackedItem.Entity.Id ==myEntityToSave.Id);
If it exists
if (isAlreadyTracked)
{
myEntityToSave= trackedEntries.First(trackedItem => trackedItem.Entity.Id == myEntityToSave.Id).Entity;
}
else
{
//Attach or Modify depending on your needs
}
I solve this problem with a "using" block
using (SqlConnection conn = new SqlConnection(connectionString))
{
// stuff to do with data base
}
// or if you are using entity framework
using (DataBaseEntity data = new DataBaseEntity)
{
}
Here is where I get the idea https://social.msdn.microsoft.com/Forums/sqlserver/es-ES/b4b350ba-b0d5-464d-8656-8c117d55b2af/problema-al-modificar-en-entity-framework?forum=vcses is in spanish (look for the second answer)
you can use added method like;
_dbContext.Entry(modelclassname).State = EntityState.Added;
but in many case if you want to use more than one model at that time this won't work because entity is already attached to another entity. So, at that time you can use ADDOrUpdate Entity Migration method which simply migrates object from one to another and as a result you wouldn't get any error.
_dbContext.Set<modelclassname>().AddOrUpdate(yourmodel);
Clear all State
dbContextGlobalERP.ChangeTracker.Entries().Where(e => e.Entity != null).ToList().ForEach(e => e.State = EntityState.Detached);
Reasons I've encountered this error:
Did not use .AsNoTracking() when querying for existing entities. Especially when calling a helper function to check permissions.
Calling .Include() on a query and then trying to edit the parent. Example: var ent = repo.Query<Ent>().Include(e=>e.Ent2).First(); ...repo.Edit(e.Ent2); repo.Edit(e); If I'm going to edit a nested object, I try to separate these into separate query calls now. If you can't do that, set the child object to null and iterate through lists, detaching objects like this
Editing an old entity in a Put web call. The new item is already added to the repo, so modify that one and have it be saved in super.Put(). Example of what will throw an error: public void Put(key, newItem){ var old = repo.Query<Entity>().Where(e=>Id==key).First(); ... repo.Edit(old); super.Put(key,newItem); ... }
Multiple helper functions edit the same entity. Instead of passing the ID as a parameter into each function, pass a reference to the entity. Error solved!
In my case , I had wrote really two times an entity of same type . So I delete it and all things work correctly
This problem may also be seen during ViewModel to EntityModel mapping (by using AutoMapper, etc.) and trying to include context.Entry().State and context.SaveChanges() such a using block as shown below would solve the problem. Please keep in mind that context.SaveChanges() method is used two times instead of using just after if-block as it must be in using block also.
public void Save(YourEntity entity)
{
if (entity.Id == 0)
{
context.YourEntity.Add(entity);
context.SaveChanges();
}
else
{
using (var context = new YourDbContext())
{
context.Entry(entity).State = EntityState.Modified;
context.SaveChanges(); //Must be in using block
}
}
}