☕ NEW! 完成新手任務即可參加抽獎!LINE 星巴克禮券等你拿,名額有限!        🎉 推廣活動:邀請好友註冊 DevLearn,累積推薦抽 LINE 星巴克禮券! 活動詳情 →        🔥 活動期間 2026/4/1 - 5/31 |已有 0 人參加       
concept-backend 中級

EF Core:Repository Pattern 要不要用?

爭議:DbContext 本身就是 Repository + Unit of Work

EF Core 的 DbContext 已經實作了:
- Repository Pattern → DbSet<T> 就是 Repository
- Unit of Work → SaveChanges() 就是 Commit

再包一層 Repository,不就是多此一舉?

支持用 Repository 的理由

// 1. 抽象化:Controller 不直接依賴 EF Core
public interface IUserRepository {
    Task<User?> GetByIdAsync(int id);
    Task<List<User>> GetActiveUsersAsync();
}

// 好處:換 ORM(Dapper)或換 DB(MongoDB)不影響上層
// 好處:單元測試可以 mock IUserRepository

反對用 Repository 的理由

// 1. 「洩漏抽象」:你最終還是會暴露 IQueryable
public interface IUserRepository {
    IQueryable<User> GetAll(); // ← 這不就是 DbSet 嗎?
}

// 2. 重複包裝:每個 CRUD 都要寫一層
public async Task<User?> GetByIdAsync(int id) {
    return await _db.Users.FindAsync(id); // 一行就結束,何必包?
}

// 3. 複雜查詢怎麼辦?
// 最終 Repository 會變成一個巨大的「查詢方法集」
GetUsersByAgeAndCityAndStatusOrderByNamePaginated(...)

實務建議

場景 建議
小型專案(< 20 表) 直接用 DbContext,不需要 Repository
中型專案 用 Service Layer + DbContext
需要換 ORM 的可能性 用 Repository
需要大量單元測試 用 Repository(方便 mock)
複雜的查詢邏輯 用 Specification Pattern 或 Query Object
// 推薦的中間路線:Service Layer(不需要 Repository)
public class UserService {
    private readonly AppDbContext _db;
    public UserService(AppDbContext db) => _db = db;

    public async Task<User?> GetActiveUser(int id) {
        return await _db.Users
            .AsNoTracking()
            .Where(u => u.Id == id && u.IsActive)
            .FirstOrDefaultAsync();
    }
}
// 直接在 Service 裡寫查詢邏輯,不多包一層

結論:沒有絕對的對錯。重要的是統一團隊風格,而不是追求「正確」的架構。

💡 大家的想法 · 0

載入中...
💬 即時聊天室 🟢 0 人在線
😀 😎 🤓 💻 🎮 🎸 🔥
➕ 新問題
📋 我的工單
💬 LINE 社群
🔒
需要註冊才能使用此功能
註冊帳號即可解鎖測驗、遊戲、簽到、筆記下載等所有功能,完全免費!
免費註冊