如何使用Entity Framework在Web API操作中提交对象图

时间:2014-01-30 18:46:35

标签: entity-framework asp.net-web-api

我正在开发一个WebAPI v2操作方法,以使用Entity Framework 6持久更新对象图,我有点不确定我是否有正确的语法。 Project 是我的根类型,其中包含 Question 的集合。 Project 已经存在,但Post操作可能需要提交对 Project 属性的更改,对现有 Question 的更改并添加新< EM>问题的

我的代码在下面显示和评论,但是当我想要有一个帮助方法可以为我做一些帮助时,更新需要大量的工作:

[System.Web.Http.Route("{id:int}")]
public HttpResponseMessage Post(int id, [FromBody]Project project)
{
    // Validate the submitted project
    if (!ModelState.IsValid)
        return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);

    // Fetch the existing project. This is here to perform row-level
    // security check. The user will have logged on and this confirms the 
    // organisation they work for. Behind the scenes I will compound the
    // query below to include a check for organisation id. This prevents
    // users submitted any project id and overwriting data that isn't theirs.
    // Would it make the pattern below better if this only executed a .Count()?
    // Would that mean the context would then be tracking the project before 
    // the update?
    var existingProject = _context.Projects.Include("Questions").FirstOrDefault(p => p.ProjectId == id);
    if (existingProject == null)
        return Request.CreateErrorResponse(HttpStatusCode.NotFound, ModelState);

    // Copy model updates to the project
    var projectEntry = _context.Entry(existingProject);
    projectEntry.CurrentValues.SetValues(project);

    // Now work out which questions are updates or additions
    foreach (var question in project.Questions)
    {
        // No id so must be an addition
        if (question.QuestionId == 0)
        {
            existingProject.Questions.Add(question);
        }
        else
        {
            // Fetch the existing question so we can copy values
            var existingQuestion = existingProject.Questions.FirstOrDefault(q => q.QuestionId == question.QuestionId);
            if (existingQuestion == null)
            {
                // In a single user system finding ourselves here should not
                // be possible. Ideally we'll need to do some concurrency
                // when other users make updates or have some record locking
                // mechanism.
                existingProject.Questions.Add(question);
            }
            else
            {
                var questionEntry = _context.Entry(existingQuestion);
                questionEntry.CurrentValues.SetValues(question);
            }
        }
    }

    _context.SaveChanges();

    return Request.CreateResponse(HttpStatusCode.Created, project);
}

更新:我在提交之后也意识到我甚至没有处理删除问题的问题,但是看看上面的解决方案,我不会目前正在照顾,所以我很感激被考虑。

1 个答案:

答案 0 :(得分:0)

看起来你正在寻找Trackable-Entities,这里是wiki标题:

可跟踪实体支持跟踪对象图中实体的更改,以便将它们发送到Web服务并保存在单一往返和< em>单笔交易。此功能作为一组NuGet packages提供。

服务器端NuGet包为Entity Framework的ApplyChanges类提供DbContext扩展方法,该类遍历一个或多个对象图,通知实体框架每个实体的更改状态。调用SaveChanges后,您可以调用AcceptChanges将所有实体的状态设置为Unchanged,然后再将其返回给客户端。还有一个LoadRelatedEntities方法,您可以调用该方法来填充已添加实体的参考属性。

客户端软件包提供更改跟踪器,用于在将实体插入,修改或删除时将实体标记为AddedModifiedDeleted对象图中的任何级别。要开始跟踪更改,只需将一个或多个实体添加到ChangeTrackingCollection,然后将Tracking属性设置为true即可。如果要保留更改,可以在更改跟踪器上调用GetChanges以仅获取更改的项目,这样就不需要将未更改的实体发送到服务器,从而节省带宽并提高性能。可跟踪实体将关联实体,以便您可以通过调用MergeChanges将更新的实体合并回原始对象图。虽然您当然可以手动设置TrackingState实体,但更改跟踪器部署为可移植类库,因此您可以从任何.NET客户端(包括桌面或移动应用程序)使用它。 / p>

另一个需要考虑的项目是Breeze#