rust-dix 集成与注册模式

`rust-ef` 与 `rust-dix` DI 容器深度集成,支持构造函数注入和 owned/shared 两种解析模式。

基础注册

use rust_dix::*;
use rust_ef::di::*;
use rust_ef::db_context::DbContext;
use rust_ef_sqlite::DbContextOptionsBuilderExt as _;

let provider = ServiceCollection::new()
    .add_dbcontext(|options| {
        options.use_sqlite("data source=app.db");
    })
    .build()
    .unwrap();

// 推荐:owned 解析,直接 &mut self 访问
// rust-dix 0.6+: get_owned() 返回 Result<T, RdiError>
let mut ctx: DbContext = provider.get_owned().unwrap();

// 或:共享解析(Arc<DbContext>,&self 访问,同一 scope 内共享)
// use rust_dix::scope::ScopeFactory;
// let scope = provider.create_scope();
// let ctx: Arc<DbContext> = scope.get().unwrap();

在 Handler 中注入

`#[derive(Inject)]` 要求 bare `T` 字段标记 `#[inject(owned)]`(`Arc<T>` 字段标记 `#[inject]`),未标记字段走 `Default::default()`。Handler 方法使用 `&mut self`:

use rust_webapp::*;
use rust_ef::db_context::DbContext;

#[derive(Inject)]
pub struct ListBlogsHandler {
    #[inject(owned)]
    ctx: DbContext,  // bare T + #[inject(owned)] → get_owned()
}

#[inject(scoped)]
#[async_trait]
impl IRequestHandler<ListBlogsRequest, Vec<BlogDto>> for ListBlogsHandler {
    async fn handle(&mut self, _req: ListBlogsRequest) -> Result<Vec<BlogDto>> {
        let blogs = self.ctx.set::<Blog>().query().to_list().await?;
        Ok(blogs.into_iter().map(BlogDto::from).collect())
    }
}

Repository 封装模式

pub struct BlogRepository {
    ctx: DbContext,
}

impl BlogRepository {
    pub async fn list_high_rated(&mut self) -> EFResult<Vec<Blog>> {
        let set = self.ctx.set::<Blog>();
        let expr = linq!(|b: Blog| b.rating > 4);
        set.filter(expr).to_list().await
    }
}

设计要点

| 实践 | 说明 | |------|------| | Owned 解析(推荐) | `get_owned()` → `DbContext`,`&mut self` 访问,无需锁 | | Shared 解析 | `scope.get()` → `Arc<DbContext>`,`&self` 访问,同一 scope 内共享 | | 每个请求一个 DbContext | Scoped 生命周期,避免跨请求跟踪污染 | | `#[derive(Inject)]` 显式标记 | bare `T` + `#[inject(owned)]` → owned;`Arc<T>` + `#[inject]` → shared;未标记 → `Default` |

下一节:[多数据库 Keyed 注册](keyed-databases.md)