.NET Core 5中如何在静态方法中注入Database对象?
可行解决方案
方案一:将查询逻辑抽离为仓储类(推荐)
把实体类的查询逻辑移到专门的仓储类中,让实体仅作为数据载体,避免业务逻辑与实体耦合,同时完美适配依赖注入。
- 定义仓储接口:
public interface IPersonRepository { IEnumerable<Person> GetAll(); }
- 实现仓储类,注入
IDatabase:
public class PersonRepository : IPersonRepository { private readonly IDatabase _database; public PersonRepository(IDatabase database) { _database = database; } public IEnumerable<Person> GetAll() { using var connection = _database.GetConnection(); return connection.Query<Person>("SELECT * FROM Persons"); } }
- 在
Startup.cs中注入仓储:
services.AddScoped<IPersonRepository, PersonRepository>();
- 使用时直接注入
IPersonRepository调用即可,比如在控制器中:
public class PersonController : Controller { private readonly IPersonRepository _personRepo; public PersonController(IPersonRepository personRepo) { _personRepo = personRepo; } public IActionResult Index() { var persons = _personRepo.GetAll(); return View(persons); } }
这个方案符合单一职责原则,实体类只负责存储数据,查询逻辑由仓储类处理,完全避开了Dapper对实体构造的限制。
方案二:给静态查询方法传入IDatabase实例
如果坚持要在实体类中保留查询方法,可以修改静态方法,让调用者传入已注入的IDatabase实例,这样既不破坏实体的无参构造(满足Dapper要求),又能使用依赖注入的连接。
修改Person类的静态方法:
public class Person { // 实体属性 public int Id { get; set; } public string Name { get; set; } public static IEnumerable<Person> GetAll(IDatabase database) { using var connection = database.GetConnection(); return connection.Query<Person>("SELECT * FROM Persons"); } }
调用时,从依赖注入容器中获取IDatabase传入:
// 比如在控制器中 public class PersonController : Controller { private readonly IDatabase _database; public PersonController(IDatabase database) { _database = database; } public IActionResult Index() { var persons = Person.GetAll(_database); return View(persons); } }
这个方案保留了实体类中的查询逻辑,同时避免了硬编码连接字符串,也不影响Dapper的实体映射。
方案三:使用服务定位器(应急方案,不推荐)
如果以上两种方案都无法满足需求,可以临时使用服务定位器模式,从DI容器中直接获取IDatabase实例,但这种方式会让代码耦合DI容器,不利于测试和维护,仅作为应急手段。
- 在
Program.cs中保存服务提供者(.NET Core 5的Program结构):
public static class Program { public static IServiceProvider ServiceProvider { get; private set; } public static void Main(string[] args) { var host = CreateHostBuilder(args).Build(); ServiceProvider = host.Services; host.Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }); } }
- 在
Person类的静态方法中获取IDatabase:
public static IEnumerable<Person> GetAll() { using var scope = Program.ServiceProvider.CreateScope(); var database = scope.ServiceProvider.GetRequiredService<IDatabase>(); using var connection = database.GetConnection(); return connection.Query<Person>("SELECT * FROM Persons"); }
注意:必须创建作用域(CreateScope)来获取Scoped生命周期的IDatabase,否则会导致生命周期管理问题。
内容的提问来源于stack exchange,提问作者Ahmad
相关产品推荐
相关产品推荐

