I already make code in c# like this
IList<BookViewModel> ListBook= _bookService.GetListById(BookViewModel);
foreach (BookViewModel apart in ListBook)
{
apart.Status = "Published";
_bookService.Update(apart);
}
and code update in my repository like this.
public virtual TEntity Update(TEntity updatingObject)
{
this.GetDbSet<TEntity>().Attach(updatingObject);
this.SetEntityState(updatingObject, EntityState.Modified);
this.UnitOfWork.SaveChanges();
return updatingObject;
}
and my method
public IList<BookViewModel> GetListById(BookViewModel bookVM)
{
Expression<Func<Book, bool>> criteria = c => c.IdBook == bookVM.Id Book;
return this.GetList(criteria);
}
but i have error
Attaching an entity of type 'Models.Book' 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.
can any one have suggestion for change code update method, i already read many reference but it's different. thank's!
for this question i have some solution for update entity i use
Entity framework extended.. this already in nugget..
Entity framework Extended
Related
I have a situation where I am mapping DTO -> Database Entity using automapper.
var entityObj = _mapper.Map<REQUESTEXT>(reqDTO);
Then I am using entityObj to update the record in the database.
void Update(REQUESTEXT entityObj)
{
_context.REQUESTEXTs.Attach(entityObj); <--- Error
_context.Entry(entityObj).Property(x => x.CUSTOPTIONCD).IsModified = true;
_context.SaveChanges();
}
When i am trying to attach REQUESTEXT object to context, its giving me an error:
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.
As per this SO answer: https://stackoverflow.com/a/23228001/1169180 I need to use AsNoTracking(), I am not sure how to use that in AutoMapper?
Any suggestions?
AsNoTracking refers to when the entities are loaded by the context, not Automapper. You are getting the error because at some point in that DbContext's life, it has loaded the entity with that ID and is tracking it. The option they recommended is to change over your entity loading to use AsNoTracking which effectively tells EF not to track the entity when it is read.
An alternative solution to that problem is to check for the existence of the entity in the DbContext's local cache first, and if found, use AutoMapper to map your property changes across to that existing entity, rather than creating a new entity.
For example:
var existingEntity = _context.REQUESTEXTs.Local.SingleOrDefault(x => x.EntityId == reqDTO.EntityId);
if(existingEntity != null)
mapper.Map(reqDto, existingEntity);
else
{
var entityObj = _mapper.Map<REQUESTEXT>(reqDTO);
_context.REQUESTEXTs.Attach(entityObj);
_context.Entry(entityObj).Property(x => x.CUSTOPTIONCD).IsModified = true;
}
_context.SaveChanges();
This checks the local cache for an existing entity, (does not hit DB) and if found, it uses AutoMapper to update it's properties. The entity tracking will note the changes, so when SaveChanges is called, the modifications would go through to the DB. If the local cache does not have the entity, then we create a new instance, attach it, mark it as modified, and save.
One suggestion that appears to be missing in your example: You should be validating the assumptions that:
The ID in your DTO actually does exist in the database before attempting this
and
The record being modified can, and should be editable by the user making this request.
and
The data being updated is fully validated.
If this is a web application /w an accessible Controller action or Web API endpoint, this could be exploitable to allow users to edit records they otherwise should not be able to, or update records in ways they should not be. (Trust nothing from a client request.) Each request should be validated thoroughly, and any deviation detected should terminate the client session.
I'm using EF code first to control my data. I have two models, ElectricitySite and ElectricitySiteSplit.
ElectricitySite contains List<ElectricitySiteSplits> ElectricitySiteSplits, this is a one to many relationship.
I'm trying to write my Update method for the repository layer which will deal with both the tables, so far I have:
public void UpdateElectricitySite(ElectricitySite updatedElectricitySite)
{
var dbElectricitySite = GetElectricitySite(updatedElectricitySite.ElectricitySiteId);
_context.ElectricitySites.Attach(updatedElectricitySite);
_context.Entry(updatedElectricitySite).State = EntityState.Modified;
_context.SaveChanges();
}
I get the following error when I click the Save button:
Attaching an entity of type
'MySolution.Repo.ElectricityModels.ElectricitySiteSplit' 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.
I think this is because I've not attached my ElectricitySiteSplit entity however if I add this in below my ElectricitySites attachment:
_context.ElectricitySiteSplits.Attach(updatedElectricitySite.SiteSplits);
I get this error:
Severity Code Description Project File Line Suppression State
Error CS1503 Argument 1: cannot convert from
'System.Collections.Generic.List'
to 'UtilityBilling.Repo.ElectricityModels.ElectricitySiteSplit'
How do I handle the ElectricitySiteSplits table update which is contained in updatedElectrcitiySite.SiteSplits as a list.
FYI - I've already looked here:
Entity Framework 5 Updating a Record
https://msdn.microsoft.com/en-gb/data/jj592676.aspx
EF does not handle both tables automatically. I have to specify which item was added/updated/removed. Take a look at this thread Cleanly updating a hierarchy in Entity Framework
Hope this helps!
I'm using Entity Framework. I want to load an entity, edit it, and save the changes back in the DB. But no matter if I've edited a foreign key property or a simple property, EF gives me the following error:
Attaching an entity of type 'ClassX' 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.
Please note that ClassX is not a direct virtual property of the class that I'm trying to update, instead it's a virtual property in some of the other classes that my class has navigation properties to them.
I've read some related issues. But I didn't really get how I should apply them to my own problem, since I'm using a generic repository as posted below.
public class GenericRepository<T> where T : class
{
private EFDbContext context = new EFDbContext();
public IEnumerable<T> GetAll()
{
return context.Set<T>();
}
public void Insert(T entity)
{
context.Set<T>().Add(entity);
context.SaveChanges();
}
public void Update(T entity)
{
context.Entry(entity).State = System.Data.Entity.EntityState.Modified;
context.SaveChanges();
}
//removed for brevity
}
I've encountered another problem related to virtual properties and I was advised to use ViewModels and Object to Object mapping.
As far as I got it, there's 3 options:
Use ViewModels and object-to-object mapping. I'm not going with this one, it was really painful since o2o mapping libraries have lots of bugs.
Somehow uses reference. But I can't do that since the repository is generic. Maybe I should use reflection API for that?
Delete all virtual properties. It is actually an option, since they're creating more problems than they solve.
Can anyone please explain why this problem happens and what's the easiest way to solve it?
When you set the State of an entity to Modified it also attaches all children (entities referenced by navigation properties) with State == EntityState.Unchanged. If your context already has entities with the same key, it will raise that error.
If you want those entities to be ignored, there are a few options I can think of:
Create a new data context within Update, and don't worry about the children entities because with EntityState.Unchanged, when you call SaveChanges, they'll be ignored. This probably doesn't make sense if you're using some kind of Repository Pattern.
Go through the navigation properties you don't want to attach and set to null before setting State = EntityState.Modified
After setting State = EntityState.Modified, for child entities you want to ignore, set State = EntityState.Detached
Edit
It would also be good to figure out why the context would end up with multiple child entities with the same key in the first place.
I'm using EF6, with a Repository pattern (a repository has its own context instance). When I use FindAsync to obtain and modify an entity, the changes are not tracked, and so any properties that are edited are not saved upon SaveChanges. However, I also expose the table through the repository via IQueryable, and if I obtain an entity that way, all changes are saved properly. I'm trying to figure out why changes are not tracked when I use the FindAsync method.
My Find repo method:
public async Task<CDCRoute> FindDrivingRouteAsync(long routeId, string userId)
{
var route = await routeContext.Routes.FindAsync(routeId);
if (route != null && route.CDCUserInfoId == userId)
{
return route;
}
return null;
}
Table exposed with IQueryable:
public IQueryable<CDCRoute> Routes
{
get { return routeContext.Routes; }
}
Accessing a route via Find (does not save changes when modified):
routeRepo.FindDrivingRouteAsync(message.RouteId, message.UserId);
Accessing a route via the exposed IQueryable (does save changes when modified):
routeRepo.Routes.FirstOrDefault(r => r.RouteId == message.RouteId && r.CDCUserInfoId == message.UserId);
I'm sure I am missing something (am somewhat new to EF), so any help would be greatly appreciated, thanks!
I just had this problem - I suspect it's a bug with EF, since manually updating the EntityState & then forcing the context to save changes, or using the Synchronous version of the same method in the same Microsoft EntityFramework library, caused no issues.
Specifically, when using the Microsoft.AspNet.Identity.EntityFramework library & UserStore/UserManager classes, when an object was retrieved using FindAsync, subsequent modifications were not properly tracked by Entity Framework.
I.e. was getting this error after FindAsync, then trying to update the DB:
Attaching an entity of type 'MyNamespace.MyUser' 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.
My UpdateAsync method that was failing looked like this:
public async Task UpdateAsync(MyUser user)
{
var result = await _manager.UpdateAsync(user); //State = EntityState.Unchanged
//UpdateAsync above is directly inherited from Microsoft.AspNet.Identity.EntityFramework.UserManager<T>
//ERROR! Primary key duplicate (Default identity method doing Attach :/ )
}
Eventually through tracking I found that the EntityState was still "Unchanged" even though changes were made. I then changed the code to this:
public async Task UpdateAsync(MyUser user)
{
_store.Context.Entry(user).State = EntityState.Modified;
var result = await _store.Context.SaveChangesAsync();
//var result = await _manager.UpdateAsync(user);
}
..the changes were then picked up & auto-magically updated in the DB. A completely synchronous Find & Update (using the same library) also allowed the Entity to be tracked & updated - this solution I deemed less acceptable than a workaround.
I'm not 100% certain it's a bug, but if this is verified by enough people, someone should open a ticket with MSFT.
Is it possible in EntityFramework 6 to add/remove related entities without actual fetching the related entities?
I was trying:
var a = new EntityA()
a.B = new EntityB { Id = 2 };
db.Entry(a).State = EntityState.Added;
db.SaveChanges();
The entity with Id already exists in DB. My attempt fails with the following exception:
Attaching an entity of type 'EntityB' 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.
To solve your exact error you need to set db.Entry( b ).State of the new B entity to Unchanged (your code results in Added)