Reputation: 3445
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.
Upvotes: 3
Views: 3033
Reputation: 522
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")
Upvotes: 3