如何将通用存储库(或业务逻辑层)注入 ViewModel

Posted

技术标签:

【中文标题】如何将通用存储库(或业务逻辑层)注入 ViewModel【英文标题】:How to Inject Generic Repository(Or Business Logic Layer) Into ViewModel 【发布时间】:2021-01-17 19:37:09 【问题描述】:

为简单起见,我想将通用存储库注入到视图模型中。我将 ViewModel 和 Repository 添加到服务集合中,ViewModel 依赖于 Repository。根据我的阅读,应该自动解析 ViewModel 的构造函数参数,因为它使用的是 IConfiguration。我已经尝试在 Services 中显式实例化 ViewModel,但仍然出现相同的运行时错误,并且在创建存储库的另一个实例时似乎无法达到目的。

Repository/IRepository 看起来像这样

    public class Repository<TPoco, TDatabaseConnection> : IRepository<TPoco, TDatabaseConnection>
            where TPoco : class
            where TDatabaseConnection : IDbConnection, new()
    

        public Repository(IConfiguration configuration, string connectionName = "DefaultConnection" )//SqlConnectionConfiguration configuration) //(string connectionString)
        
            _connectionString = configuration.GetConnectionString(connectionName);
            _configuration = configuration;
        


...

查看模型

    public class PersonViewModel
    
        private IRepository<Person, IDbConnection> _PersonRepository;

        public List<Person> Persons  get; set; 

        public PersonViewModel(IRepository<Person, IDbConnection> personRepository)
        
            _PersonRepository=personRepository;
        
...

在 Startup.cs 文件中,我添加如下服务:

    services.AddScoped<IRepository<Person, SQLiteConnection>, Repository<Person, SQLiteConnection>>();
    services.AddScoped<PersonViewModel>();  //runtime errors here

我收到两个运行时错误 (System.AggregateException)


Inner Exception 1:
InvalidOperationException: Error while validating the service descriptor 'ServiceType: BlazorInjection.ViewModels.PersonViewModel Lifetime: Scoped ImplementationType: BlazorInjection.ViewModels.PersonViewModel': Unable to resolve service for type 'DapperRepository.IRepository`2[BlazorInjection.Models.Person,System.Data.IDbConnection]' while attempting to activate 'BlazorInjection.ViewModels.PersonViewModel'.

Inner Exception 2:
InvalidOperationException: Unable to resolve service for type 'DapperRepository.IRepository`2[BlazorInjection.Models.Person,System.Data.IDbConnection]' while attempting to activate 'BlazorInjection.ViewModels.PersonViewModel'.

我错过了一个概念吗?我该如何纠正这个问题?

【问题讨论】:

这可能对stevejgordon.co.uk/…有帮助 【参考方案1】:

将类结构更改为:

public class PersonViewModel

    private IRepository<Person> _PersonRepository;

    public List<Person> Persons  get; set; 

    public PersonViewModel(IRepository<Person> personRepository)
    
        _PersonRepository = personRepository;
    


public interface IDbConnection




public class Person  


public interface IRepository<TPoco>  

public class SQLiteConnection : IDbConnection 

    private string _connectionString;
    private IConfiguration _configuration;

    public SQLiteConnection(IConfiguration configuration, string connectionStringName)
    
        _connectionString = configuration.GetConnectionString(connectionStringName);
        _configuration = configuration;
    


public class Repository<TPoco> : IRepository<TPoco>
    where TPoco : class

    public IDbConnection Connection  get; 

    public Repository(IDbConnection connection)
    
        Connection = connection;
    

Startup.cs相比,只需更改为

services.AddScoped<IDbConnection>(sp => ActivatorUtilities.CreateInstance<SQLiteConnection>(sp, "defaultConnectionStringName"));
        services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
        services.AddScoped<PersonViewModel>();

注意通用存储库注册,它可以轻松扩展您的数据层。 ActivatorUtilities 允许您将当前范围 container 服务与自定义参数结合起来。从设计的角度来看,我认为这种方式(一个通用的注入连接)也更好,因为您的存储库客户端不需要知道底层数据库实现。

【讨论】:

我试过了。我收到关于隐式转换的错误:There is no implicit reference conversion from 'DapperRepository.Repository&lt;BlazorInjection.Models.Person, System.Data.SQLite.SQLiteConnection&gt;' to 'DapperRepository.IRepository&lt;BlazorInjection.Models.Person, System.Data.IDbConnection&gt;'.Does System.Data.SQLiteConnection not implement IDbConnection? 也试过了。类似的错误。它要求参数,所以我这样做了。 services.AddScoped&lt;IRepository&lt;Person, IDbConnection&gt;&gt;(sp =&gt; new Repository&lt;Person, SQLiteConnection&gt;(Configuration)); 我收到两个错误:CS1662 Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type 和第二个要求明确 cast.hmm ? 有什么理由需要存储库是双重通用的吗?如果没有,您可以将 IDbConnection 作为构造函数参数 我让我的存储库实例化 dbconnection。我想没有必要。我可以尝试将其作为参数传入 请查看修改后的答案

以上是关于如何将通用存储库(或业务逻辑层)注入 ViewModel的主要内容,如果未能解决你的问题,请参考以下文章

存储过程中的所有业务逻辑

服务层如何适应我的存储库实现?

当使用实体框架作为数据访问层时,如何实现业务逻辑层?

Gin实现依赖注入

基于Spring4+Hibernate4的通用数据访问层+业务逻辑层(Dao层+Service层)设计与实现!

用于业务逻辑或数据访问层的 Web 服务