C# Web API 2:更新导航属性(实体)

C# Web API 2:更新导航属性(实体),c#,asp.net,wcf,entity-framework,asp.net-web-api,C#,Asp.net,Wcf,Entity Framework,Asp.net Web Api,我正在寻找一些关于Web API功能的指导,这些功能在MVC中很容易更新具有导航属性的实体 在MVC中,其实现方式如下: [AcceptVerbs(HttpVerbs.Post)] [ValidateAntiForgeryToken] public virtual async Task<ActionResult> Update(Page page) { Guard.IsNotNull(page, "page"); va

我正在寻找一些关于Web API功能的指导,这些功能在MVC中很容易更新具有导航属性的实体

在MVC中,其实现方式如下:

    [AcceptVerbs(HttpVerbs.Post)]
    [ValidateAntiForgeryToken]
    public virtual async Task<ActionResult> Update(Page page)
    {
        Guard.IsNotNull(page, "page");

        var pageToUpdate = await this.repository.Query.Include(p => p.Tags).Include(p => p.Name).SingleOrDefaultAsync(p => p.Pk == page.Pk);

        if (pageToUpdate == null)
        {
            return this.RedirectToRoute(H.Constants.Routes.Error.Index, new
                                                                        {
                                                                            view = H.Constants.Views.Error.ViewPages.NotFound
                                                                        });
        }

        if (this.TryUpdateModel(pageToUpdate))
        {
            this.repository.BeginTransaction();

            this.repository.Update(pageToUpdate); // Updates related entities!

            await this.repository.CommitTransactionAsync();

            return this.RedirectToRoute(H.Constants.Routes.Data.Read);
        }

        return this.View(H.Constants.Views.FolderNames.ViewPages.FormatWith(H.Constants.Views.Data.ViewPages.Update), pageToUpdate);
    }
[AcceptVerbs(HttpVerbs.Post)]
[ValidateAntiForgeryToken]
公共虚拟异步任务更新(第页)
{
Guard.IsNotNull(第页,“第页”);
var pageToUpdate=wait this.repository.Query.Include(p=>p.Tags).Include(p=>p.Name).SingleOrDefaultAsync(p=>p.Pk==page.Pk);
如果(pageToUpdate==null)
{
返回此.RedirectToRoute(H.Constants.Routes.Error.Index,新建
{
视图=H.Constants.Views.Error.ViewPages.NotFound
});
}
if(此.TryUpdateModel(pageToUpdate))
{
this.repository.BeginTransaction();
this.repository.Update(pageToUpdate);//更新相关实体!
等待此消息。repository.CommitTransactionAsync();
返回此.RedirectToRoute(H.Constants.Routes.Data.Read);
}
返回this.View(H.Constants.Views.FolderNames.ViewPages.FormatWith(H.Constants.Views.Data.ViewPages.Update),pageToUpdate);
}
所有的导航属性都会更新,生活也会很好

在WebAPI中尝试这一点时,并没有这么多。相关实体未更新。例如:

    [HttpPatch]
    [HttpPut]
    public virtual async Task<IHttpActionResult> Update(int pk, Page page)
    {
        Guard.IsNotNegativeOrZero(pk, "pk");

        if (this.ModelState.IsValid)
        {
            if (page.Pk == pk)
            {
                try
                {
                    this.repository.BeginTransaction();

                    this.repository.Update(page); // Doesn't update related entities.

                    await this.repository.CommitTransactionAsync();

                    return this.StatusCode(HttpStatusCode.NoContent);
                }
                catch (DbUpdateConcurrencyException dbUpdateConcurrencyException)
                {
                    if (this.repository.Query.Any(p => p.Pk == pk))
                    {
                        return this.InternalServerError(dbUpdateConcurrencyException);
                    }

                    return this.NotFound();
                }
            }

            return this.BadRequest();
        }

        return this.BadRequest(this.ModelState);
    }
[HttpPatch]
[HttpPut]
公共虚拟异步任务更新(int-pk,第页)
{
卫兵。不负或零(pk,pk);
if(this.ModelState.IsValid)
{
如果(page.Pk==Pk)
{
尝试
{
this.repository.BeginTransaction();
this.repository.Update(第页);//不更新相关实体。
等待此消息。repository.CommitTransactionAsync();
返回此.StatusCode(HttpStatusCode.NoContent);
}
捕获(DbUpdateConcurrencyException DbUpdateConcurrencyException)
{
if(this.repository.Query.Any(p=>p.Pk==Pk))
{
返回此.InternalServerError(dbUpdateConcurrencyException);
}
返回此.NotFound();
}
}
返回此.BadRequest();
}
返回此.BadRequest(此.ModelState);
}
这在今天的Web API中可以实现吗?或者Web API当前是不完整的Microsoft产品


编辑:WebAPI中不存在使用示例更新且未引用WCF的TryUpdateModel。您可能还发现您在实体的序列化方面存在问题。出于这两个原因,我使用将ViewModels映射到EF实体,您可以使用automapper中的映射来处理导航属性

web API方法如下所示:

    public HttpResponseMessage Post(MyViewModel model)
    {
        if (someValidationCheckHere)
            return new HttpResponseMessage(HttpStatusCode.BadRequest);

        _myService.Update(Mapper.Map<MyViewModel, MyEntity>(model));

        return new HttpResponseMessage(HttpStatusCode.OK);
    }
公共httpresponsemessagepost(MyViewModel模型)
{
如果(someValidationCheckHere)
返回新的HttpResponseMessage(HttpStatusCode.BadRequest);
_myService.Update(Mapper.Map(model));
返回新的HttpResponseMessage(HttpStatusCode.OK);
}
正如其他人所说,服务最终由存储库进行更新。在本例中,我将使用automapper忽略导航属性,但您可以配置automapper以按自己喜欢的方式处理它们:

        Mapper.CreateMap<MyViewModel, MyEntity>()
            .ForMember(x => x.NavigationProperty, opt => opt.Ignore());
Mapper.CreateMap()
.FormMember(x=>x.NavigationProperty,opt=>opt.Ignore());

我在global.asax中的application\u start静态类中设置了所有映射。

您是否混淆了传输层(WCF/WebAPI)和ORM?我不明白
context.Update(entity)
与WebAPI有什么关系。不,它是WCF和WebAPI背后的实体框架,每个都有不同的行为。WebAPI很好,只是你用错了。WebApi与它处理web请求的数据和实体无关。Api控制器应获取输入并将其发送给服务,服务将更新实体等。@RyanMendoza,什么是
上下文。更新
?听起来像是ORM。如果是这样的话,那绝对与WebAPI无关。我不确定我的问题是否翻译得很好。例如,在MVC中有UpdateModel和TryUpdateModel,允许方法接收部分模型并只更新模型的相关部分。这在WebAPI中并不存在,尽管它似乎是以MVC为模型的。您好,感谢您的回复。您能否在提供的示例中提供一个AutoMappers角色的示例,以解决TryUpdateModel的不足?