我一直在研究更新现有的代码库,以便更好地遵循设计模式,原理,处理单元测试,分离问题等等。我是新手来实现很多这些概念所以我仍然在进行大量的研究和尝试看看如何在当前的代码库中实现它们。
目前,每个业务实体都有自己的vb文件。在该vb文件中包含该实体的实体,实体集合和实体dalc类。如果要对实体执行数据库操作,可以通过调用Enity.Save,Entity.Delete等来实现。实体类上的这些方法将创建实体dalc对象,然后调用Save,Delete等方法。在实体dalc对象上。然后,dalc将通过处理低级别内容的SqlHelper类调用Save,Delete等存储过程。
每个实体类都需要将一个Location对象传递给它的构造函数。此对象用于了解用户登录的数据库以及为数据库创建适当的连接字符串。数据库都具有相同的模式;它们只有不同的名称,可以存在于不同的SQL实例中。基本上每个客户端都有自己的数据库,并且Location对象会根据存储在cookie中的客户端名称来查找共享数据库,以找出客户端需要连接的SQL实例。
我一直在研究更多的模型/存储库/服务方法,但是Location对象让我失望,特别是因为它也需要访问数据库以获取创建正确连接字符串所需的信息。存储库对象需要连接字符串,但我看到的所有示例都在类中进行了硬编码。我认为存储库对象需要接受Location对象的接口,但我不确定MVC项目是直接执行还是将其传递给服务对象,他们会处理它。在什么时候创建Location对象,因为它也需要访问数据库才能创建连接字符串,它是如何创建的?
我也不清楚MVC项目如何与Service和Repository层交互。似乎所有内容都应该通过服务对象运行,但是对于测试,您可能希望它们接收存储库的接口。这样做意味着MVC项目需要传入存储库对象,但似乎MVC项目不应该知道存储库对象。但是,如果您只是在进行基本的CRUD,那么让MVC项目直接在存储库对象上调用这些方法而不是通过服务对象运行它们似乎会更简单。
这是我目前正在研究的一个例子。计划现在使用ADO.NET和SQL Server,但将来可能会切换到ORM甚至是不同的SQL后端。我希望模型/存储库/服务方法能够在将来轻松地进行这些更改,所以如果不能随时提供相关建议。
Project.Model
public class Person
{
public int Id;
public string Name;
}
Project.Repository
public class PersonRepository
{
public Person FindById(int id)
{
// Connect to the database based on the Location's connection string
}
}
Project.Service
public class PersonService
{
private IPersonRepository _personRepository;
// Should this even take in the repository object?
public PersonService(IPersonRepository personRepository)
{
_personRepository = personRepository;
}
// Should the MVC project call this directly on the repository object?
public Person FindById(int id)
{
return _personRepository.FindById(id);
}
}
Project.MCV
// I think the Location object needs to come from here, as the client name is
// in the cookie. I'm not sure how the controllers should interact with the
// service and repository classes.
答案 0 :(得分:1)
我是第二个@Christian的建议。使用ORM将极大地简化您与底层数据存储的交互;和NHibernate是一个很好的选择。
但是,在您的示例中,从演示文稿(也称为ASP.NET MVC项目)与数据层交互的常用方法是将服务作为控制器的依赖项注入。
有几种方法可以做到这一点,最简单,最直接的是use a dependency injection framework (like Unity)来实例化您在控制器的构造函数中指定的服务,
public class PersonController : Controller
{
private readonly IPersonService personService;
public PersonController(IPersonService personService)
{
this.personService = personService;
}
}
另一种方法是implement your own ControllerFactory
implementation并根据需要注入所需的服务。这项工作要多得多,但如果你有时间,你可以了解一下ASP.NET MVC路由流程的全部流程以及一些DI本身。
在DI框架中,您(大部分)使用具体类实现注册 interfaces ,基本上说当需要IPersonRepository
的实例时,请使用新的PersonRepositoryImpl
的实例。有了这些注册规则,DI框架将以递归方式实例化类构造函数中出现的每个依赖项。*
换句话说,当您请求PersonController
的实例时,DI框架将尝试创建类型为PersonController
的实例;当它看到构造函数需要类型IPersonService
的参数时,它首先尝试基于相同的规则实例化一个。因此,该过程再次开始,直到所有依赖关系都已解析并注入PersonController
的构造函数,
resolve PersonController
-> construct PersonController(IPersonService personService)
-> resolve IPersonService with PersonService
-> construct PersonService(IPersonRepository personRepository)
-> resolve IPersonRepository with PersonRepository
-> construct PersonRepository() <- this one has no dependencies
备份堆栈,直到返回PersonController
的新实例。
*为了使其工作,您必须只有给定类的一个公共构造函数,其中每个参数都是需要解析的依赖项(您的示例将其固定下来)。如果未在框架中注册依赖项的类型,则解析将失败。如果有多个公共构造函数,解决方案也将失败(没有确定的方法来确定使用哪个),除非您注册应该使用哪个构造函数(通常使用属性,但它取决于DI框架)。一些DI框架(如Unity)可能允许您根本没有构造函数(默认为空的无参数构造函数),并且具有依赖属性标记的公共属性。我建议不使用此方法,因为它无法从使用者类中了解该类需要哪些依赖项(不使用Reflection来检查所有属性并查看哪些属性被标记为依赖项),这将是反过来导致无数NullReferenceException
s。