DTO(Data Transfer Objects) 中文叫做「資料傳輸物件」,就是單純用來「傳輸」用的,例如在不同的系統層之間,或是與外部系統溝通使用的。
上面的內容是指 Users 和 UserClaims 資料表關聯,如果直接把 User 這個 Model 當作 API 的回應物件,其他人就可以知道我們系統的架構,並且還會因為包含了多餘的內容,浪費系統資源。並且假設今天 API 有要多傳幾個欄位,那我們又會修改到和這件事情本身完全無關的 Model,本來資料庫不需要多幾個欄位,但是因為 API 需要,所以又開了欄位,但其實單獨建立一個 API 用的 class,也就是 DTO 就可以解決問題。
並且還不會讓各服務都過於依賴單個的物件,讓一個物件只負責一件事情,達成解耦合和單一職責。
我們可以利用 getter, setter 或是 Attribute 加上一些驗證:
但是不會包含邏輯或是行為,也不需要被封裝,不會有私有(private)或受保護(protected)的屬性,他應該只是單純的用來「傳輸資料」,所以結構應該盡可能的簡單。
我們很常會在命名結尾加入 DTO 或是使用符合 C# 大駝峰命名方式的 Dto,不過這也不是必須的,甚至有些人推崇不要加上 DTO 字眼。在使用功能分組時,通常會建立一個 DTO 資料夾(或是 Dto),在裡面放入本功能的所有相關 DTO ,而如果這些 DTO 的命名足夠清楚,那就不需要在 DTO 的名稱後面加上 DTO 了。
為什麼要使用 DTO?
假設使用 Entity Framework Core 存取資料庫,在資料庫對應模型(Model)中我們很常會看到類似下面的定義:
[Table("Users")]
public partial class User
{
[Key]
public string Id { get; set; } = null!;
[StringLength(256)]
public string UserName { get; set; } = null!;
[InverseProperty("User")]
public virtual ICollection<UserClaim> UserClaims { get; set; } = new List<UserClaim>();
}
上面的內容是指 Users 和 UserClaims 資料表關聯,如果直接把 User 這個 Model 當作 API 的回應物件,其他人就可以知道我們系統的架構,並且還會因為包含了多餘的內容,浪費系統資源。並且假設今天 API 有要多傳幾個欄位,那我們又會修改到和這件事情本身完全無關的 Model,本來資料庫不需要多幾個欄位,但是因為 API 需要,所以又開了欄位,但其實單獨建立一個 API 用的 class,也就是 DTO 就可以解決問題。
並且還不會讓各服務都過於依賴單個的物件,讓一個物件只負責一件事情,達成解耦合和單一職責。
DTO 要保持簡單
DTO 應該只是用來傳輸資料的,例如傳輸使用者個人資訊的 UserProfileDto:
public class UserProfileDto
{
public int Id { get; set; }
public string Username { get; set; }
public string Email { get; set; }
public string FullName { get; set; }
public string PhoneNumber { get; set; }
}
我們可以利用 getter, setter 或是 Attribute 加上一些驗證:
public class UserProfileDto
{
public int Id { get; set; }
[Required]
[MaxLength(10)]
public string Username { get; set; }
public string Email { get; set; }
public string FullName { get; set; }
public string PhoneNumber { get; set; }
}
但是不會包含邏輯或是行為,也不需要被封裝,不會有私有(private)或受保護(protected)的屬性,他應該只是單純的用來「傳輸資料」,所以結構應該盡可能的簡單。
DTO 命名
DTO 會專注於單一功能,而這個功能應該反映在名稱上,例如接收使用者登入請求的 DTO: UserLoginRequest
public class UserLoginRequest
{
public string UserName { get; set; }
public string Password { get; set; }
}
我們很常會在命名結尾加入 DTO 或是使用符合 C# 大駝峰命名方式的 Dto,不過這也不是必須的,甚至有些人推崇不要加上 DTO 字眼。在使用功能分組時,通常會建立一個 DTO 資料夾(或是 Dto),在裡面放入本功能的所有相關 DTO ,而如果這些 DTO 的命名足夠清楚,那就不需要在 DTO 的名稱後面加上 DTO 了。
感謝教學~
回覆刪除