Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Pobieranie ukończonego projektu
W tej chwili nasz internetowy interfejs API uwidacznia jednostki bazy danych klientowi. Klient otrzymuje dane, które odwzorowują się bezpośrednio na tabele twojej bazy danych. Jednak nie zawsze jest to dobry pomysł. Czasami chcesz zmienić kształt danych wysyłanych do klienta. Na przykład możesz chcieć:
- Usuń odwołania cykliczne (zobacz poprzednią sekcję).
- Ukryj określone właściwości, których klienci nie powinni wyświetlać.
- Pomiń niektóre właściwości, aby zmniejszyć rozmiar ładunku.
- Spłaszczanie struktur obiektów zawierających zagnieżdżone obiekty, aby były bardziej wygodne dla klientów.
- Unikaj luk w zabezpieczeniach związanych z nadmierną ekspozycją danych. (Zobacz Walidacja modelu, aby zapoznać się z omówieniem nadmiernego publikowania).
- Rozdziel warstwę usługi z warstwy bazy danych.
W tym celu można zdefiniować obiekt transferu danych (DTO). Obiekt DTO to obiekt definiujący sposób wysyłania danych za pośrednictwem sieci. Zobaczmy, jak to działa z jednostką Book. W folderze Models dodaj dwie klasy 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; }
}
}
Klasa BookDetailDto zawiera wszystkie właściwości z modelu Książki, z tą różnicą, że AuthorName jest to ciąg, który będzie zawierać nazwę autora. Klasa BookDto zawiera podzbiór właściwości z BookDetailDtoklasy .
Następnie zastąp dwie metody GET w BooksController klasie wersjami, które zwracają obiekty DTO. Użyjemy instrukcji LINQ Select, aby przekonwertować encje Book na 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);
}
Oto baza danych SQL wygenerowana przez nową GetBooks metodę. Widać, że program EF tłumaczy pozycję LINQ Select na instrukcję 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]
Na koniec zmodyfikuj metodę PostBook, aby zwrócić 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);
}
Uwaga / Notatka
W tym samouczku konwertujemy na DTO manualnie w kodzie. Inną opcją jest użycie biblioteki, takiej jak AutoMapper , która automatycznie obsługuje konwersję.