混淆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。所以我的问题是:

  1. 如何使用EF更新儿童收藏?意味着如果数据库中不存在新的,我需要添加它,否则需要更新,或者如果POST中删除了它,我需要从数据库中删除。

  2. 如果我不使用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框架抛出错误,因为它认为我有重复的数据。这实际上是如何工作的?

  3. 正如您所看到的,我正在尝试将objFromDbobj进行比较,以检查用户是否删除了其中一个详细信息,这样我就可以将其从数据库中删除。相反,我从收集结果中得到了一堆DynamicProxies。什么是DynamicProxies,它是如何工作的?

  4. EF有什么好文章或101教程吗?到目前为止,我只看到了一个简单的问题,它对我的情况没有帮助,我环顾四周,发现了一个如何做事的复杂答案。老实说,在这一点上,我希望我只使用经典的ADO.Net而不是EF。

混淆EF中的跟踪(使用子集合更新实体)

为了更好地理解实体框架,可以将DbContext视为应用程序和数据库之间的代理。DbContext将缓存所有内容,并将使用缓存值中的每一位数据,除非您告诉它不要这样做

对于1.:这取决于您的环境,如果在选择和更新实体之间没有部署DbContext,您只需调用SaveChanges即可保存数据。如果已释放DbContext,则可以从上下文中分离实体,更改数据,重新附加它们,并将EntityState设置为已修改。

我不能给你一个100%肯定的答案,因为我大约半年前就停止使用实体框架了。但我知道更新复杂的关系是一件痛苦的事。

对于2.:命令AsNoTracking告诉EF不要跟踪对此查询内实体所做的更改。例如,从数据库中选择5个时间表,更改第一个实体中的一些值并删除最后一个。DbContext知道第一个实体发生了更改,最后一个实体被删除,如果您调用SaveChangesDbContext将自动更新第一个实体,删除最后一个,并保持其他实体不变。现在您尝试自己更新一个实体,并将第一个实体再次附加到DbContext。

DbContext现在将有两个具有相同键的实体,这将导致异常。

对于3.DynamicProxies是实体框架用来跟踪这些实体的更改的对象。

对于4.:查看此链接,还有一本关于实体框架6的好书(标题:"编程实体框架"(