2 回答

TA貢獻1765條經驗 獲得超5個贊
在這種情況下注入具體實現是錯誤的嗎?
這取決于。如果您正在編寫一個具有分離關注點(業務邏輯、驗證、授權)的多層應用程序,或者您正在編寫一個 5 頁的應用程序來為有限數量的用戶顯示雜項信息?
我已經為小型的、主要是只讀的應用程序完成了這些,因為只有很小的變化,我不需要過度設計和構建解決方案。
如果是,我怎么能只注入一個接口而不是注入一個具體的實現呢?
當然,但是在某些時候,一個類將需要一個 dbcontext,它可以由需要它的對象進行 DI 或創建。如果您確實將數據訪問抽象到一個單獨的類/接口中,我不會推薦 DI(將上下文注入具體的數據訪問),因為該具體類型將與 EF 緊密耦合。這意味著如果您決定切換到 Dapper、NHibernate 或其他一些 ORM,您無論如何都必須重寫所有方法。
一種快速而骯臟的方法(對于小型/學習經驗,我永遠不會向百萬用戶系統推薦這種方法)來抽象掉它DbContext很簡單:
public interface IUserDA
{
IQueryable<User> Users { get; }
}
public class MyDbContext : IUserDA
{
public DbSet<User> Users { get; set; }
IQueryable<User> IUserDA.Users
{
get
{
return Users; // references the DbSet
}
}
}
現在您的 MyDbContext 實現了一個未耦合到實體框架的接口。
但是如果我們注入一個具體的類,它會破壞 DI 的目的嗎?
取決于你的目的。您究竟希望通過使用 DI 實現什么?您真的要編寫真正的單元測試嗎?您真的看到自己為多個安裝/租戶更改或擁有多個接口實例嗎?

TA貢獻1828條經驗 獲得超6個贊
我不建議將 Entity Framework 抽象出來,因為它本身已經是一個抽象(您可以在您的消費類不知情的情況下將數據庫提供程序從 SQL Server 換成 PostgreSQL)。我也不建議將您的上下文注入您的控制器。
我喜歡做的是采用Command Pattern,利用令人驚嘆的 Jimmy Bogard 庫AutoMapper和MediatR,自己研究一下它是否合適。
為您提供一個基本示例,說明使用此類架構設計選擇時控制器的外觀:
[Route("api/[controller]")]
[ApiController]
public class SomeTypeController : ControllerBase
{
private readonly IMediator mediator;
private readonly IMapper mapper;
public SomeTypeController(IMediator mediator, IMapper mapper)
{
this.mediator = mediator;
this.mapper = mapper;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<SomeTypeContract>>> GetAll(CancellationToken cancellationToken)
{
var result = await mediator.Send(new GetAllSomeTypeRequest(), cancellationToken);
return Ok(mapper.Map<IEnumerable<SomeTypeContract>>(result));
}
}
我真的很喜歡這個,因為現在您的控制器充當業務邏輯的路由器。他們幸福地不知道引擎蓋下究竟發生了什么(或者它是如何發生的)。
要了解問題的核心:
在這種情況下注入具體實現是錯誤的嗎?
對此的答案有點固執己見,但許多人認為這不僅是一個可以接受的選擇,而且是正確的選擇。在某個時間點,為了進行實際的數據庫查詢,您需要了解您的 DBContext。
通過將其抽象出來,您只會通過編寫數百種不同的方法來以不同的方式查詢您的數據、執行各種操作而給自己帶來selects痛苦includes。否則,您將擁有“笨拙”的方法,這些方法返回的數據比您實際需要的多得多。
通過具體了解您的 DBContext(如果您使用命令模式,可能在您的請求處理程序中),您可以完全控制數據的獲取方式,允許查詢優化以及強制關注點分離。
免責聲明:我提出上述庫是因為它們很棒且很有幫助,但我知道很多人看不起將它們包含在答案中。我只想說清楚,它們絕不是執行命令模式的必要條件,但如果您要采用它,為什么要重新發明輪子?
- 2 回答
- 0 關注
- 107 瀏覽
添加回答
舉報