混淆EF中的跟踪(使用子集合更新实体)
本文关键字:子集合 更新 实体 EF 跟踪 混淆 | 更新日期: 2023-09-27 18:16:16
所以我是EF的新手(我使用的是EF6(,我在理解这个概念时遇到了问题,我正在尝试用子集合更新实体。
这是我的实体类:
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; }
}
我的更新方法:
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);
}
上面的代码给我Attaching an entity of type 'ClassName' failed because another entity of the same type already has the same primary key value
。所以我的问题是:
如何使用EF更新儿童收藏?意味着如果数据库中不存在新的,我需要添加它,否则需要更新,或者如果
POST
中删除了它,我需要从数据库中删除。如果我不使用
AsNoTracking()
,它将抛出Saving or accepting changes failed because more than one entity of type 'ClassName' have the same primary key value
。我注意到这个错误是由我的DbSet
引起的,如果我不使用AsNoTracking()
,则将来自DB的数据添加到它的Local
属性中,这导致EF框架抛出错误,因为它认为我有重复的数据。这实际上是如何工作的?正如您所看到的,我正在尝试将
objFromDb
和obj
进行比较,以检查用户是否删除了其中一个详细信息,这样我就可以将其从数据库中删除。相反,我从收集结果中得到了一堆DynamicProxies
。什么是DynamicProxies
,它是如何工作的?EF有什么好文章或101教程吗?到目前为止,我只看到了一个简单的问题,它对我的情况没有帮助,我环顾四周,发现了一个如何做事的复杂答案。老实说,在这一点上,我希望我只使用经典的ADO.Net而不是EF。
为了更好地理解实体框架,可以将DbContext
视为应用程序和数据库之间的代理。DbContext
将缓存所有内容,并将使用缓存值中的每一位数据,除非您告诉它不要这样做
对于1.:这取决于您的环境,如果在选择和更新实体之间没有部署DbContext
,您只需调用SaveChanges
即可保存数据。如果已释放DbContext
,则可以从上下文中分离实体,更改数据,重新附加它们,并将EntityState
设置为已修改。
我不能给你一个100%肯定的答案,因为我大约半年前就停止使用实体框架了。但我知道更新复杂的关系是一件痛苦的事。
对于2.:命令AsNoTracking
告诉EF不要跟踪对此查询内实体所做的更改。例如,从数据库中选择5个时间表,更改第一个实体中的一些值并删除最后一个。DbContext
知道第一个实体发生了更改,最后一个实体被删除,如果您调用SaveChanges
,DbContext
将自动更新第一个实体,删除最后一个,并保持其他实体不变。现在您尝试自己更新一个实体,并将第一个实体再次附加到DbContext。
DbContext现在将有两个具有相同键的实体,这将导致异常。
对于3.:DynamicProxies
是实体框架用来跟踪这些实体的更改的对象。
对于4.:查看此链接,还有一本关于实体框架6的好书(标题:"编程实体框架"(