依赖注入概念问题:在哪里实例化新对象以保存到数据库?
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<AnonymousLogin> repository
传递给AnonymousLoginService
意味着AnonmyousLoginService
依赖于IRepository<AnonymousLogin>
。它与传递给方法的参数无关。
如果你觉得最好在方法中进行关注点分离并实例化新的db模型来验证它是否有效,而不是接受用户输入作为db模型并传入。没关系。
在一个单独的应用程序中拥有域层并没有错。特别是如果您不想为每个构建的应用程序创建一个新的域层。可以通过这种方式使用域层来松散地耦合代码,并为多个应用程序提供一个域层。假设方法返回类型、方法名称和方法参数不变,对领域层的更改不应破坏任何依赖它的项目。
就让 api 了解两种类型的模型(db 和 api 模型)而言,这听起来比让领域层了解两种类型的模型要好得多。领域层只知道领域模型可能会更好,然后每个使用领域层的应用程序也可以访问领域模型。与其让领域层理解来自多个项目的模型,唯一需要考虑的是领域模型应该有多安全?可能有一组虚拟域模型(面向公众的数据库模型)和一组私有数据库模型(实际数据库模型),并且域层可以访问虚拟模型,然后从那里实例化实际的数据库模型。确保封装了实际的逻辑和代码。
【讨论】:
以上是关于依赖注入概念问题:在哪里实例化新对象以保存到数据库?的主要内容,如果未能解决你的问题,请参考以下文章