1️⃣ IQuery<T> คืออะไร?

By suparat · 08 Oct 2025


โอเคครับ 😎 เรามาไล่ตั้งแต่ พื้นฐานจนถึงการใช้งาน IQuery<AppLogDto> ในสไตล์ C# / .NET Core กันเลย


1️⃣ IQuery<T> คืออะไร?

โดยทั่วไป IQuery<T> มักจะถูกใช้ใน CQRS (Command Query Responsibility Segregation) pattern

  • Query → ใช้สำหรับ อ่านข้อมูล (Read)

  • Command → ใช้สำหรับ เขียน/แก้ไขข้อมูล (Write)

IQuery<T> มักถูกออกแบบเป็น interface ที่ระบุว่า “Query นี้จะคืนค่าเป็น T

ตัวอย่างโครงสร้างง่าย ๆ:

public interface IQuery<T>
{
    // อาจจะมี property สำหรับ filter หรือ paging
}

แล้วเวลาเรียกใช้ เราจะมี Query Handler มาทำงานกับ Query นี้:

public interface IQueryHandler<TQuery, TResult>
    where TQuery : IQuery<TResult>
{
    Task<TResult> HandleAsync(TQuery query);
}

2️⃣ AppLogDto คืออะไร?

AppLogDto คือ Data Transfer Object (DTO) สำหรับเก็บข้อมูล log ของแอป

ตัวอย่าง:

public class AppLogDto
{
    public int Id { get; set; }
    public string Message { get; set; }
    public string Level { get; set; } // Info, Error, Warning
    public DateTime CreatedAt { get; set; }
}

3️⃣ สร้าง Query ที่คืน AppLogDto

ตัวอย่าง: Query สำหรับดึง log ทั้งหมด:

public class GetAppLogsQuery : IQuery<IEnumerable<AppLogDto>>
{
    public string? Level { get; set; } // filter log level เช่น "Error"
    public DateTime? From { get; set; }
    public DateTime? To { get; set; }
}
  • IQuery<IEnumerable<AppLogDto>> → หมายความว่า query นี้ คืนค่าเป็นลิสต์ของ AppLogDto


4️⃣ Query Handler

public class GetAppLogsQueryHandler : IQueryHandler<GetAppLogsQuery, IEnumerable<AppLogDto>>
{
    private readonly AppDbContext _dbContext;

    public GetAppLogsQueryHandler(AppDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public async Task<IEnumerable<AppLogDto>> HandleAsync(GetAppLogsQuery query)
    {
        var logs = _dbContext.AppLogs.AsQueryable();

        if (!string.IsNullOrEmpty(query.Level))
            logs = logs.Where(x => x.Level == query.Level);

        if (query.From.HasValue)
            logs = logs.Where(x => x.CreatedAt >= query.From.Value);

        if (query.To.HasValue)
            logs = logs.Where(x => x.CreatedAt <= query.To.Value);

        return await logs
            .Select(x => new AppLogDto
            {
                Id = x.Id,
                Message = x.Message,
                Level = x.Level,
                CreatedAt = x.CreatedAt
            })
            .ToListAsync();
    }
}
  • HandleAsync จะทำ filter, map เป็น DTO และ return

  • เราใช้ IQueryable + LINQ เพื่อ query database


5️⃣ วิธีเรียกใช้งาน

สมมติมี Query Bus / Mediator:

var query = new GetAppLogsQuery
{
    Level = "Error",
    From = DateTime.UtcNow.AddDays(-7)
};

var logs = await _queryBus.SendAsync(query);

foreach (var log in logs)
{
    Console.WriteLine($"{log.CreatedAt} [{log.Level}] {log.Message}");
}

🔹 สรุป

สิ่งที่ทำ ความหมาย
IQuery<T> Interface สำหรับ query/read คืนค่า T
AppLogDto DTO เก็บข้อมูล log
IQueryHandler<TQuery, TResult> Handle query และ return TResult
GetAppLogsQuery ตัว query ที่ implement IQuery<IEnumerable<AppLogDto>>
HandleAsync ฟังก์ชันทำงานจริง query DB และ return DTO

💡 เคล็ดลับ:

  • CQRS pattern จะช่วยแยก Read กับ Write ออกจากกัน

  • IQuery<T> + IQueryHandler<TQuery, TResult> ทำให้ โค้ดอ่านง่าย ทดสอบง่าย และ maintainable


ถ้าคุณอยาก ผมสามารถ วาด diagram flow ของ IQuery ให้เห็นภาพตั้งแต่ Controller → Query → Handler → DB → DTO เลย ทำให้เข้าใจ CQRS แบบชัดเจนมากขึ้น

คุณอยากให้ผมทำ diagram นั้นไหมครับ?

CQRS
Web hosting by Somee.com