iT邦幫忙

0

Day 20|LINQ 資料查詢、篩選與排序

c#
  • 分享至 

  • xImage
  •  

今日學習目標

  • 理解 LINQ 的基本概念
  • 學會 Where、OrderBy、Select
  • 認識 IQueryable 與延遲執行
  • 替 TaskFlow 增加搜尋與篩選功能
  • 使用 Swagger UI 測試

什麼是 LINQ

LINQ 是 C# 提供的一套查詢功能,讓我們使用一致的語法處理集合與資料庫中的資料。

三個最重要的 LINQ 方法

  1. Where:篩選
var tasks = await _db.Tasks
    .Where(t => t.IsCompleted == false)
    .ToListAsync();

意思是只取得尚未完成的任務
2. OrderBy:排序
依任務編號,由小到大:

var tasks = await _db.Tasks
    .OrderBy(t => t.Id)
    .ToListAsync();
  1. Select:選擇欄位
    只取得任務名稱:
var titles = await _db.Tasks
    .Select(t => t.Title)
    .ToListAsync();

修改 ITaskService.cs

一樣使用昨天的專案

using TaskFlow3.Api.Models;

namespace TaskFlow3.Api.Services
{
    public interface ITaskService
    {
        Task<List<TaskItem>> GetAllAsync(
            bool? completed = null,
            string? keyword = null,
            string sort = "asc");

        Task<TaskItem?> GetByIdAsync(int id);

        Task<TaskItem> CreateAsync(string title);

        Task<bool> UpdateAsync(
            int id,
            string title,
            bool isCompleted);

        Task<bool> DeleteAsync(int id);
    }
}

修改 TaskService.cs

using Microsoft.EntityFrameworkCore;
using TaskFlow3.Api.Data;
using TaskFlow3.Api.Models;

namespace TaskFlow3.Api.Services
{
    public class TaskService : ITaskService
    {
        private readonly TaskFlowDbContext _db;

        public TaskService(TaskFlowDbContext db)
        {
            _db = db;
        }

        // GET:查詢、篩選、搜尋與排序
        public async Task<List<TaskItem>> GetAllAsync(
            bool? completed = null,
            string? keyword = null,
            string sort = "asc")
        {
            IQueryable<TaskItem> query = _db.Tasks
                .AsNoTracking();

            // 依完成狀態篩選
            if (completed.HasValue)
            {
                query = query.Where(
                    t => t.IsCompleted == completed.Value);
            }

            // 搜尋任務名稱
            if (!string.IsNullOrWhiteSpace(keyword))
            {
                string searchText = keyword.Trim();

                query = query.Where(
                    t => t.Title.Contains(searchText));
            }

            // 依 Id 排序
            if (sort.Equals(
                "desc",
                StringComparison.OrdinalIgnoreCase))
            {
                query = query.OrderByDescending(t => t.Id);
            }
            else
            {
                query = query.OrderBy(t => t.Id);
            }

            return await query.ToListAsync();
        }

        // GET:查詢單筆任務
        public async Task<TaskItem?> GetByIdAsync(int id)
        {
            return await _db.Tasks.FindAsync(id);
        }

        // POST:新增任務
        public async Task<TaskItem> CreateAsync(string title)
        {
            TaskItem task = new TaskItem
            {
                Title = title,
                IsCompleted = false
            };

            await _db.Tasks.AddAsync(task);
            await _db.SaveChangesAsync();

            return task;
        }

        // PUT:修改任務
        public async Task<bool> UpdateAsync(
            int id,
            string title,
            bool isCompleted)
        {
            TaskItem? task = await _db.Tasks.FindAsync(id);

            if (task == null)
            {
                return false;
            }

            task.Title = title;
            task.IsCompleted = isCompleted;

            await _db.SaveChangesAsync();

            return true;
        }

        // DELETE:刪除任務
        public async Task<bool> DeleteAsync(int id)
        {
            TaskItem? task = await _db.Tasks.FindAsync(id);

            if (task == null)
            {
                return false;
            }

            _db.Tasks.Remove(task);

            await _db.SaveChangesAsync();

            return true;
        }
    }
}

修改 TasksController.cs

using Microsoft.AspNetCore.Mvc;
using TaskFlow3.Api.DTOs;
using TaskFlow3.Api.Models;
using TaskFlow3.Api.Services;

namespace TaskFlow3.Api.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class TasksController : ControllerBase
    {
        private readonly ITaskService _taskService;

        public TasksController(ITaskService taskService)
        {
            _taskService = taskService;
        }

        // GET /api/tasks
        
    [HttpGet]
    public async Task<ActionResult<List<TaskDto>>> GetTasks(
        [FromQuery] bool? completed = null,
        [FromQuery] string? keyword = null,
        [FromQuery] string sort = "asc")
    {
        var tasks = await _taskService.GetAllAsync(
        completed,
        keyword,
        sort
    );

    var result = tasks.Select(t => ToDto(t)).ToList();

    return Ok(result);
}

        // GET /api/tasks/1
        [HttpGet("{id:int}")]
        public async Task<ActionResult<TaskDto>> GetTask(int id)
        {
            TaskItem? task = await _taskService.GetByIdAsync(id);

            if (task == null)
            {
                return NotFound("找不到這筆任務");
            }

            return Ok(ToDto(task));
        }

        // POST /api/tasks
        [HttpPost]
        public async Task<ActionResult<TaskDto>> CreateTask(
            [FromBody] CreateTaskDto input)
        {
            if (input == null ||
                string.IsNullOrWhiteSpace(input.Title))
            {
                return BadRequest("任務名稱不可空白");
            }

            TaskItem task =
                await _taskService.CreateAsync(input.Title);

            return CreatedAtAction(
                nameof(GetTask),
                new { id = task.Id },
                ToDto(task)
            );
        }

        // PUT /api/tasks/1
        [HttpPut("{id:int}")]
        public async Task<IActionResult> UpdateTask(
            int id,
            [FromBody] UpdateTaskDto input)
        {
            if (input == null ||
                string.IsNullOrWhiteSpace(input.Title))
            {
                return BadRequest("任務名稱不可空白");
            }

            bool success = await _taskService.UpdateAsync(
                id,
                input.Title,
                input.IsCompleted
            );

            if (!success)
            {
                return NotFound("找不到這筆任務");
            }

            return NoContent();
        }

        // DELETE /api/tasks/1
        [HttpDelete("{id:int}")]
        public async Task<IActionResult> DeleteTask(int id)
        {
            bool success = await _taskService.DeleteAsync(id);

            if (!success)
            {
                return NotFound("找不到這筆任務");
            }

            return NoContent();
        }

        // Model 轉成 DTO
        private static TaskDto ToDto(TaskItem task)
        {
            return new TaskDto
            {
                Id = task.Id,
                Title = task.Title,
                IsCompleted = task.IsCompleted
            };
        }
    }
}

結果
在 VS Code 終端機打:dotnet build,再執行:dotnet run
https://ithelp.ithome.com.tw/upload/images/20261022/20184430VpCfdtvUvQ.png
https://ithelp.ithome.com.tw/upload/images/20261022/20184430k7jtMZ1e3L.png
剩下的把後面部分改成底下內容即可
https://ithelp.ithome.com.tw/upload/images/20261022/20184430NHBBp9JegQ.png


*提醒邦友,使用第三方服務/API 時,請務必評估資安風險與隱私保護
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言