При создании RESTful Api с ASP.NET Core MVC 2.2 я заметил, что не было примера DTO, подобного примеру веб-API 2014 года.
ASP.NET Core MVC 2.2 Пример использования API 2019
Пример ASP.NET web-api 2014
Итак, я решил создать DTO для нескольких моих команд-контроллеров HTTPGet, HTTPPost и HTTPPut
У меня есть два вопроса из моего окончательного результата.
Это рекомендуемый способ сделать это в общем смысле. Или в новом ядре Entity Framework есть что-то, что отличается или лучше, чем в примере 2014 года, который был основан на Entity Framework 6 или предыдущих версиях?
Следует ли вообще использовать шаблон проектирования DTO? Или в Entity Framework Core есть что-то, что отличается от шаблона DTO. В частности, есть ли способ взять данные из базы данных и передать их представлению / клиенту именно так, как мне нужно, чтобы они передавались?
Дополнительные сведения о причине, по которой следует задать вопрос, часть 2. Я читал о том, что DTO является анти-паттернами, и люди говорят, что не используют их по той или иной причине. Тем не менее, многие разработчики умоляют их использовать и когда и почему их следует использовать. Личный пример для меня - работа над проектами Angular и React. Получение данных, которые мне нужны, это прекрасная вещь, которую я не могу представить ни одной другой альтернативой, которая заключалась бы в том, чтобы делать все типы обручей и разбора, чтобы пройти через монолитный объект для отображения адреса и местоположения на экране.
Но времена изменились, и существует ли шаблон проектирования или другой шаблон, который будет делать то же самое, но с меньшими затратами и вычислительными затратами.
В связи с этим, существуют ли большие вычислительные затраты для сервера и dbserver для использования этого шаблона?
И наконец, приведенный ниже код позволяет ожидать использования шаблона DTO в Entity Framework Core в отличие от EF 6 или linq to sql framework?
Я включил изменения кода ниже, чтобы проиллюстрировать мое создание DTO для модели TodoItem из нижеприведенного упражнения.
Проект (TodoApi) -> DTOs -> TodoItemDTO.cs:
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace TodoApi.Models
{
public class TodoItemDTO
{
[Required]
public string Names { get; set; }
[DefaultValue(false)]
public bool IsCompletes { get; set; }
}
public class TodoItemDetailDTO
{
public long Id { get; set; }
[Required]
public string Names { get; set; }
[DefaultValue(false)]
public bool IsCompletes { get; set; }
}
}
Проект (TodoApi) -> Контроллеры -> TodoController.cs:
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
namespace TodoApi.Controllers
{
[Produces("application/json")]
[Route("api/[controller]")]
[ApiController]
public class TodoController: ControllerBase
{
private readonly TodoContext _context;
public TodoController(TodoContext context)
{
_context = context;
if (_context.TodoItems.Count() == 0)
{
// Create a new TodoItem if collection is empty,
// which means you can't delte all TodoItems.
_context.TodoItems.Add(new TodoItem { Name = "Item1" });
_context.SaveChanges();
}
// Console.WriteLine(GetTodoItems());
}
// Get: api/Todo
[HttpGet]
public async Task<ActionResult<IQueryable<TodoItem>>> GetTodoItems()
{
var todoItems = await _context.TodoItems.Select(t =>
new TodoItemDetailDTO()
{
Id = t.Id,
Names = t.Name,
IsCompletes = t.IsComplete
}).ToListAsync();
return Ok(todoItems);
// previous return statement
//return await _context.TodoItems.ToListAsync();
}
// Get: api/Todo/5
[HttpGet("{id}")]
[ProducesResponseType(typeof(TodoItemDetailDTO), 201)]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.Select(t =>
new TodoItemDetailDTO()
{
Id = t.Id,
Names = t.Name,
IsCompletes = t.IsComplete
}).SingleOrDefaultAsync(t => t.Id == id);
if (todoItem == null)
{
return NotFound();
}
return Ok(todoItem);
//var todoItem = await _context.TodoItems.FindAsync(id);
//////if (todoItem == null)
//{
// return NotFound();
//}
//return todoItem;
}
// POST: api/Todo
/// <summary>
/// Creates a TodoItem.
/// </summary>
/// <remarks>
/// Sample request:
///
/// POST /Todo
/// {
/// "id": 1,
/// "name": "Item1",
/// "isComplete": true
/// }
///
/// </remarks>
/// <param name="item"></param>
/// <returns>A newly created TodoItem</returns>
/// <response code="201">Returns the newly created item</response>
/// <response code="400">If the item is null</response>
[HttpPost]
[ProducesResponseType(typeof(TodoItemDTO), 201)]
[ProducesResponseType(typeof(TodoItemDTO), 400)]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem item)
{
_context.TodoItems.Add(item);
await _context.SaveChangesAsync();
_context.Entry(item).Property(x => x.Name);
var dto = new TodoItemDTO()
{
Names = item.Name,
IsCompletes = item.IsComplete
};
// didn't use because CreatedAtAction Worked
// return CreatedAtRoute("DefaultApi", new { id = item.Id }, dto);
return CreatedAtAction(nameof(GetTodoItem), new { id = item.Id }, dto);
// original item call for new todoitem post
//return CreatedAtAction(nameof(GetTodoItem), new { id = item.Id }, item);
}
// PUT: api/Todo/5
[HttpPut("{id}")]
[ProducesResponseType(typeof(TodoItemDTO), 201)]
[ProducesResponseType(typeof(TodoItemDTO), 400)]
public async Task<IActionResult> PutTodoItem(long id, TodoItem item)
{
if (id != item.Id)
{
return BadRequest();
}
_context.Entry(item).State = EntityState.Modified;
await _context.SaveChangesAsync();
var dto = new TodoItemDTO()
{
Names = item.Name,
IsCompletes = item.IsComplete
};
return CreatedAtAction(nameof(GetTodoItem), new { id = item.Id }, dto);
}
// DELETE: api/Todo/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
}
}