本系列之前的文章:

在之前的基础上,增强Controller使之能涵盖CRUD的全部功能。

以下代码只针对KnowledgeItemsController。

  1. 支持Create操作,通常映射到POST方法。

在KnowledgeItemsController中加入如下方法

    // POST: /KnowledgeItems
    /// <summary>
    /// Support for creating knowledge item
    /// </summary>
    public async Task<IActionResult> Post([FromBody] Knowledge knowledge)
    {
        if (!ModelState.IsValid)
        {
            foreach (var value in ModelState.Values)
            {
                foreach(var err in value.Errors) 
                {
                    System.Diagnostics.Debug.WriteLine(err.Exception?.Message);
                }
            }

            return BadRequest();
        }

        _context.KnowledgeItems.Add(knowledge);
        await _context.SaveChangesAsync();

        return Created(knowledge);
    }

注意,因为创建KnowledgeItem必须保证数据的完整性(Model中使用Annotation),所以这里需要判断ModelState。

在Debug语境下,程序会输出所有错误信息。

  1. 对于Update操作,对应于PUT方法。

加入如下方法:

    // PUT: /KnowledgeItems/5
    /// <summary>
    /// Support for updating Knowledge items
    /// </summary>
    public async Task<IActionResult> Put([FromODataUri] int key, [FromBody] KnowledgeItem update)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        if (key != update.ID)
        {
            return BadRequest();
        }

        _context.Entry(update).State = EntityState.Modified;
        try
        {
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!_context.KnowledgeItems.Any(p => p.ID == key))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }

        return Updated(update);
    }

这里省略了与Create操作中一样的错误输出信息。

  1. 对于Delete操作,对应于DELETE方法。

加入对应方法:

    // DELETE: /KnowledgeItems/5
    /// <summary>
    /// Support for deleting knowledge item by key.
    /// </summary>
    public async Task<IActionResult> Delete([FromODataUri] int key)
    {
        var knowledge = await _context.KnowledgeItems.FindAsync(key);
        if (knowledge == null)
        {
            return NotFound();
        }

        _context.KnowledgeItems.Remove(knowledge);
        await _context.SaveChangesAsync();

        return StatusCode(204); // HttpStatusCode.NoContent
    }
  1. 另外一种Update方法,即HTTP PATCH。

加入对应方法:

    // PATCH: /KnowlegeItems
    /// <summary>
    /// Support for partial updates of knowledge items
    /// </summary>
    public async Task<IActionResult> Patch([FromODataUri] int key, [FromBody] Delta<KnowledgeItem> knowledge)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        var entity = await _context.KnowledgeItems.FindAsync(key);
        if (entity == null)
        {
            return NotFound();
        }

        knowledge.Patch(entity);

        try
        {
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!_context.KnowledgeItems.Any(p => p.ID == key))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }

        return Updated(entity);
    }
  1. 单个读,同样对应于HTTP GET操作。

跟之前的GET方法不同的是,它需要指定Key。

    /// GET: /KnowledgeItems(:id)
    /// <summary>
    /// Adds support for getting a knowledge item by key, for example:
    /// 
    /// GET /Knowledges(1)
    /// </summary>
    /// <param name="key">The key of the Knowledge item required</param>
    /// <returns>The Knowledge Item</returns>
    [EnableQuery]
    public SingleResult<KnowledgeItem> Get([FromODataUri] int key)
    {
        return SingleResult.Create(_context.KnowledgeItems.Where(p => p.ID == key));
    }
  1. 测试。

至此,这个Controller已经支持了CRUD操作,可以打开Postman等操作进行测试了。

同时,可以参阅OData官方文档关于Query Data的方法,使用OData强大的数据检索功能进行读取测试。

项目Repo: Link

是为之记。
Alva Chien
2020.07.04
更新于2020.12.17