这是如何使用实体框架核心和 ASP.NET 核心MVC 2.2+和3.0创建数据传输对象(DTO)



在使用ASP.NET Core MVC 2.2创建一个RESTFUL API时,我注意到没有像2014 Web API示例这样的DTO示例。

asp.net核心MVC 2.2 REST API 2019示例

ASP.NET Web-API 2014示例

所以,我决定为我的一些控制器动词httpget,httppost和httpput创建DTO

我的最终结果有2倍的问题。

  1. 这是一般意义上的推荐方法。还是在新实体框架核心中有与基于实体框架6或以前的2014示例不同或更好的东西?

  2. 通常应该使用DTO设计模式吗?或者,实体框架核心中是否存在与DTO模式完全不同的东西。特别是有一种方法可以从数据库中获取数据并以我需要将其传递给视图/客户端的数据库?

提出问题第2部分的原因的更多背景。我已经读过有关DTO是反pates的,人们说由于某种原因或其他原因不使用它们。但是,许多开发人员恳求他们的用法以及何时以及为什么使用它们。对我来说,一个个人的例子是工作和角度和反应项目。接收我需要的数据是一件美丽的事物,我无法想象其他任何其他替代方案都是进行所有类型的箍和解析,以通过单片对象,以将地址和位置显示在屏幕上。

,但时间变化了,是否有一种设计模式或其他模式可以做完全相同的事情,但费用较低和计算成本。

  1. 因此,使用此模式的服务器和DBSERVER是否有很大的计算成本?

  2. 最后,下面的代码是否期望如何在实体框架核心中使用DTO模式,而不是EF 6或LINQ到SQL Frameworks?

我已在下面包含了代码更改,以说明我从下面的练习中为托迪特模型创建的DTO创建。

project(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; }
    }
}

project(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();
        }
    }
}

我认为您太挂在语义上了。严格来说,与"值对象"之类的东西相反,"实体"只是具有身份(即具有标识符(的对象(即具有标识符(。实体框架(核心或否(是一个对象持久性的对象/关系映射器(ORM(。被馈送到EF的"实体"是代表持久性层中对象的类(即特定表中的一行(。仅此而已。

但是,在其他情况下,它通常并不是非常有用。SRP(单一责任原则(几乎表明,实体应仅关注对持久性重要的实际内容。处理特定请求的需求,用数据等特定视图可以并且会与之分歧,这意味着您要么需要使实体类做得太多,要么需要专门用于这些目的的其他类。这就是DTO,查看模型等事物的概念。

发挥作用。

简而言之,正确的事情是在特定情况下使用有意义的方法。如果您要处理CRUD型API,则在这种情况下直接使用实体类可能是有意义的。但是,即使在Crud的情况下,通常仍然更喜欢拥有自定义类将请求主体绑定到的情况。这使您可以控制序列化以及哪些属性可查看,可编辑等。从某种意义上说,您将API与持久性层解耦,使两者可以彼此独立地工作。

例如,假设您需要更改实体上的属性名称。如果您的API直接使用该实体,则需要对API进行版本并处理以前版本的旧属性名称。使用每个单独的类,您可以简单地更改映射层,而API则不愿意。客户与API交互无需更改。通常,您想始终追求组件之间最少耦合的路径。

最新更新