Bagikan melalui


Membuat Objek Transfer Data (DTO)

Unduh Proyek yang Selesai

Saat ini, API web kami mengekspos entitas database kepada klien. Klien menerima data yang memetakan langsung ke tabel database Anda. Namun, itu tidak selalu ide yang baik. Terkadang Anda ingin mengubah bentuk data yang Anda kirim ke klien. Misalnya, Anda mungkin perlu:

  • Hapus referensi melingkar (lihat bagian sebelumnya).
  • Sembunyikan properti tertentu yang tidak seharusnya dilihat klien.
  • Hilangkan beberapa properti untuk mengurangi ukuran payload.
  • Meratakan grafik objek yang berisi objek berlapis, untuk membuatnya lebih nyaman bagi klien.
  • Hindari kerentanan "posting berlebihan". (Lihat Validasi Model untuk diskusi tentang posting berlebihan.)
  • Memisahkan lapisan layanan Anda dari lapisan database Anda.

Untuk mencapai hal ini, Anda dapat menentukan objek transfer data (DTO). DTO adalah objek yang menentukan bagaimana data akan dikirim melalui jaringan. Mari kita lihat cara kerjanya dengan entitas Buku. Di folder Model, tambahkan dua kelas DTO:

namespace BookService.Models
{
    public class BookDto
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public string AuthorName { get; set; }
    }
}

namespace BookService.Models
{
    public class BookDetailDto
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public int Year { get; set; }
        public decimal Price { get; set; }
        public string AuthorName { get; set; }
        public string Genre { get; set; }
    }
}

Kelas BookDetailDto mencakup semua properti dari model Buku, kecuali itu AuthorName adalah string yang akan menyimpan nama pembuat. Kelas BookDto berisi subset properti dari BookDetailDto.

Selanjutnya, ganti dua metode GET di BooksController kelas , dengan versi yang mengembalikan DTO. Kita akan menggunakan pernyataan LINQ Select untuk mengonversi dari entitas Buku menjadi DTO.

// GET api/Books
public IQueryable<BookDto> GetBooks()
{
    var books = from b in db.Books
                select new BookDto()
                {
                    Id = b.Id,
                    Title = b.Title,
                    AuthorName = b.Author.Name
                };

    return books;
}

// GET api/Books/5
[ResponseType(typeof(BookDetailDto))]
public async Task<IHttpActionResult> GetBook(int id)
{
    var book = await db.Books.Include(b => b.Author).Select(b =>
        new BookDetailDto()
        {
            Id = b.Id,
            Title = b.Title,
            Year = b.Year,
            Price = b.Price,
            AuthorName = b.Author.Name,
            Genre = b.Genre
        }).SingleOrDefaultAsync(b => b.Id == id);
    if (book == null)
    {
        return NotFound();
    }

    return Ok(book);
}

Berikut adalah SQL yang dihasilkan oleh metode baru GetBooks . Anda dapat melihat bahwa EF menerjemahkan LINQ Select ke dalam pernyataan SQL SELECT.

SELECT 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Title] AS [Title], 
    [Extent2].[Name] AS [Name]
    FROM  [dbo].[Books] AS [Extent1]
    INNER JOIN [dbo].[Authors] AS [Extent2] ON [Extent1].[AuthorId] = [Extent2].[Id]

Terakhir, ubah PostBook metode untuk mengembalikan DTO.

[ResponseType(typeof(BookDto))]
public async Task<IHttpActionResult> PostBook(Book book)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    db.Books.Add(book);
    await db.SaveChangesAsync();

    // New code:
    // Load author name
    db.Entry(book).Reference(x => x.Author).Load();

    var dto = new BookDto()
    {
        Id = book.Id,
        Title = book.Title,
        AuthorName = book.Author.Name
    };

    return CreatedAtRoute("DefaultApi", new { id = book.Id }, dto);
}

Catatan

Dalam tutorial ini, kita mengonversi ke DTO secara manual dalam kode. Opsi lain adalah menggunakan pustaka seperti AutoMapper yang menangani konversi secara otomatis.