亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

避免將具體的數據庫上下文類注入控制器

避免將具體的數據庫上下文類注入控制器

C#
拉風的咖菲貓 2022-11-21 21:38:41
我正在使用 Entity Framework Core for MySql 和數據庫優先方法。搭建好數據庫后,生成上下文類:sakilaContext.cs(sakila是MySql內置的數據庫/scheme,我用來玩玩的)。我在 Startup.cs 中注入了我的數據庫public void ConfigureServices(IServiceCollection services)    {        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);        var connectionString = @"server=localhost;port=1123;user=root;password=xxx;database=sakila";        services.AddDbContext<sakilaContext>(options => options.UseMySql(connectionString));    }在我的 api 控制器中,我這樣做:private sakilaContext dbCtx;public SakilaController(sakilaContext dbContext){    dbCtx = dbContext;}只是個小疑問,在這種情況下注入具體實現是錯誤的嗎?如果是,我怎么能只注入一個接口而不是注入一個具體的實現呢?
查看完整描述

2 回答

?
POPMUISE

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 實現什么?您真的要編寫真正的單元測試嗎?您真的看到自己為多個安裝/租戶更改或擁有多個接口實例嗎?


查看完整回答
反對 回復 2022-11-21
?
30秒到達戰場

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(如果您使用命令模式,可能在您的請求處理程序中),您可以完全控制數據的獲取方式,允許查詢優化以及強制關注點分離。


免責聲明:我提出上述庫是因為它們很棒且很有幫助,但我知道很多人看不起將它們包含在答案中。我只想說清楚,它們絕不是執行命令模式的必要條件,但如果您要采用它,為什么要重新發明輪子?


查看完整回答
反對 回復 2022-11-21
  • 2 回答
  • 0 關注
  • 107 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號