依赖注入概念问题:在哪里实例化新对象以保存到数据库?

Posted

技术标签:

【中文标题】依赖注入概念问题:在哪里实例化新对象以保存到数据库?【英文标题】:Dependency Injection conceptual problem: where to instantiate new object to save to the db? 【发布时间】:2021-07-29 02:25:48 【问题描述】:

我正在开发一个小型玩具程序,以学习有关 .Net Core 3.1 上的 DI 和 IoC 的一些基础知识。

我有几个问题,主要是关于何时何地执行某些操作。

我为我的项目创建了以下架构:

DAL 层,Database First,具有 db 实体、上下文和实体扩展,以及存储库的通用实现:

public class Repository<T> : IRepository<T> where T : BaseEntity

    private readonly DbContext context;
    private DbSet<T> entities;
    string errorMessage = string.Empty;

    public Repository(DbContext context)
    
        this.context = context;
        entities = context.Set<T>();
    

    public IEnumerable<T> GetAll()
    
        return entities.AsEnumerable();
    
    public T Get(Guid id)
    
        //return entities.SingleOrDefault(s => s. == id);
        return null;
    
    public void Insert(T entity)
    
        try
        
            if (entity == null)
            
                throw new ArgumentNullException("entity");
            
            entities.Add(entity);
            context.SaveChanges();
        
        catch (Exception e)
        
            //log ERROR
        
    
    public void Update(T entity)
    
        try
        
            if (entity == null)
            
                throw new ArgumentNullException("entity");
            
            context.SaveChanges();
        
        catch (Exception e)
        

            //log error
        
    
    public void Delete(T entity)
    
        try
        
            if (entity == null)
            
                throw new ArgumentNullException("entity");
            
            entities.Remove(entity);
            context.SaveChanges();
        
        catch (Exception e)
        

            //log error
        
    

    public void SoftDelete(T entity) 
        try
        
            if (entity == null)
            
                throw new ArgumentNullException("entity");
            
            //context.SoftDelete(entity as EntityEntry);
            //context.SaveChanges();
        
        catch (Exception e)
        

            //log error
        
    

我还有一个服务层和一个 WebAPI 层,采用单体架构(所有服务都在同一个包中,所有 API 请求都针对所述包中的某个服务类)。

所有真正的业务逻辑都在服务层中,除了公共层中的一些实用程序、异常和通用函数。

另外,我有一个“域”层,其中有 API 模型。例如,这些模型是我在接收 POST 请求时使用的模型。

我现在最大的问题是:我在哪里/何时以及如何创建数据库实体的新实例(来自 API 模型)?

现在我的服务层中有这个:

public class AnonymousLoginService : IAnonymousLoginService

    public IRepository<AnonymousLogin> _repository  get; set; 

    public AnonymousLoginService(IRepository<AnonymousLogin> repository)
    
        _repository = repository;
    


    public void SaveNewLogin(AnonymousLoginModel newEntry)
    
        //HOW TO DO THIS CORRECTLY?
        var itemToSave = new AnonymousLogin();
        itemToSave.Username = newEntry.Username;
        itemToSave.Id = Guid.NewGuid();
        itemToSave.IsDeleted = false;
        itemToSave.LoginDate = DateTimeOffset.Now.ToString();
        itemToSave.Ipaddress = newEntry.Ipaddress;

        ValidationResult validation = (ValidationResult)itemToSave.ValidateSelf<IAnonymousLogin>();

        if (validation.IsValid)
        
            _repository.Insert(itemToSave);
        
        else
            throw new Exception("OMG");
    



AnonymousLoginModel 是来自 WEB Api 的对象(从 POST 请求的主体创建的对象),AnonymousLogin 是要保存到数据库的实体。 如您所见,我正在创建AnonymousLogin 对象的一个​​新实例,但这直接违背了DI。我应该在哪里创建新条目?这个实现正确吗?服务层应该知道 Web Api 模型和 DB 对象吗?

另外,我很担心整个领域层的概念。它可以在单独的包/项目中吗?所有这些模型都应该在 Web Api 本身内部吗?以上都不是?

我非常感谢您的帮助,因为很难得到直截了当的答案(大多数在线信息都是示例,并不真正适用于这种特定情况)。提前致谢!

【问题讨论】:

我会说 API 应该“了解”领域层,而领域层应该“了解”数据库。域不应该知道 API 层(当然也不应该知道视图模型)。 “我正在创建一个 AnonymousLogin 对象的新实例,但这直接违背了 DI。” 为什么? @MarkSeemann 我想我只是在混淆概念。我不想在我的服务层中投射一个新实例,我正在考虑一个通用转换器(可能类似于 AutoMapper 的东西)来完成工作,但我认为,在这种情况下,创建一个新对象。 【参考方案1】:

依赖注入是将依赖对象传递给对象本身的概念。在这种情况下,将IRepository&lt;AnonymousLogin&gt; repository 传递给AnonymousLoginService 意味着AnonmyousLoginService 依赖于IRepository&lt;AnonymousLogin&gt;。它与传递给方法的参数无关。

如果你觉得最好在方法中进行关注点分离并实例化新的db模型来验证它是否有效,而不是接受用户输入作为db模型并传入。没关系。

在一个单独的应用程序中拥有域层并没有错。特别是如果您不想为每个构建的应用程序创建一个新的域层。可以通过这种方式使用域层来松散地耦合代码,并为多个应用程序提供一个域层。假设方法返回类型、方法名称和方法参数不变,对领域层的更改不应破坏任何依赖它的项目。

就让 api 了解两种类型的模型(db 和 api 模型)而言,这听起来比让领域层了解两种类型的模型要好得多。领域层只知道领域模型可能会更好,然后每个使用领域层的应用程序也可以访问领域模型。与其让领域层理解来自多个项目的模型,唯一需要考虑的是领域模型应该有多安全?可能有一组虚拟域模型(面向公众的数据库模型)和一组私有数据库模型(实际数据库模型),并且域层可以访问虚拟模型,然后从那里实例化实际的数据库模型。确保封装了实际的逻辑和代码。

【讨论】:

以上是关于依赖注入概念问题:在哪里实例化新对象以保存到数据库?的主要内容,如果未能解决你的问题,请参考以下文章

AutoFac依赖注入和控制反转的使用

为每个 TableViewCell 实例化新数组

SPRING01_概述配置文件bean实例化依赖注入的方式依赖注入的数据类型分模块开发API使用

关于Spring依赖注入的问题

Spring 依赖注入

Spring 依赖注入