数据访问层的静态方法与依赖注入
static methods vs dependency injection for data access layer
对于我的 ASP.NET MVC 项目,我曾经严重依赖静态方法来访问数据,有点像这样:
public class MyTable
{
public static IEnumerable<MyTable> findAll()
{
using (var connection = new SqlConnection(Provider.connString))
{
//implementation here
}
return datas;
}
public static MyTable find(guid id)
{
using (var connection = new SqlConnection(Provider.connString))
{
//implementation here
}
}
}
所以我可以在我的控制器中这样调用它们:
var datas = MyTable.findAll();
我对它很满意,但我怀疑我是否在使用它进行数据访问方面做得很好。
现在,我正在尝试将依赖注入应用于我的数据访问 class 只是为了学习目的,就像这样:
public class MyTable
{
public IDatabaseEngine _engine = null;
public MyTable()
{
}
public MyTable(IDatabaseEngine engine)
{
_engine = engine;
}
public IEnumerable<MyTable> findAll()
{
using (var connection = _engine.getConnection())
{
//implementation here
}
return datas;
}
public MyTable find(guid id)
{
using (var connection = _engine.getConnection())
{
//implementation here
}
return data;
}
}
问题是,这意味着我必须创建一个 MyTable
class 的实例来调用我的控制器上的数据访问方法,如下所示:
var table = new MyTable(new MSSQLEngine(provider.connString));
var datas = table.findAll();
好吧,要么是我没有足够的经验来解决这个问题,要么是我做错了,我觉得为我需要的每个数据访问实例化对象感到不舒服。
我的问题是
- 我是不是做错了依赖注入? (我想我是)
- 创建数据访问对象 class 以调用是好的做法吗
控制器或其他 classes?
中的数据访问方法
- 改用静态方法是好的做法吗? (就像我
在第一个例子中做)
- 如果我的 DI 实现是错误的,我该如何纠正?
您问题的答案:
- 没有,详见下文
- DI 的主要优点是依赖于抽象而非实现。您不需要创建 classes 的实例,DI 会为您完成。您只需要将接口注入您的 classes 并在您的 IoC 中注册它们。
- 不,因为您将无法为您的方法编写单元测试。
- 见下文。
要正确使用 DI,首先您需要将 MyTable
class 提取到接口中,然后将该接口注入您的控制器。
public interface IMyTable
{
IEnumerable<MyTable> findAll();
// other methods
}
public class MyTable : IMyTable
{
// your implementation
}
那么你的控制器应该是这样的:
public class YourController : Controller
{
private IMyTable myTable;
public YourController(IMyTable myTable)
{
this.myTable = myTable;
}
public ActionResult YourAction()
{
var result = myTable.findAll();
// ...
}
}
我个人使用 Castle Windsor 作为 IoC 容器,here is an example 在 ASP.NET MVC 应用程序中使用 Castle Windsor
依赖注入只是一种在实例字段中存储依赖项的技术,因此您基本上是在 MyTable
实现中正确执行它。
如果您在控制器的构造函数中获得 IDatabaseEngine
的实例,如果您要在控制器的测试中模拟数据库引擎,则可以从依赖注入中受益。您仍然需要一种方法在您的应用程序中 注入 实例。至于现在,您正在控制器中创建一个具体的 class MSSQLEngine
实例,因此没有任何好处。
在这种情况下使用静态方法并不好,因为在您决定实施与数据库无关的测试时,您需要重构为使用实例。从最小的测试设置开始是一个很好的做法,这样您就可以在项目生命周期的早期阶段实现可测试性。我建议在你的代码库变大之前完成这个困难的部分。
了解如何在控制器中注入 IDatabaseEngine
的实例,并编写一个利用依赖注入的最小测试。大多数 MVC 框架都允许设置 IoC 容器作为工厂。在测试中,您需要使用一些模拟实现或模拟框架,例如 Moq 来构成 IDatabaseEngine
.
的实例
虽然 DI 在某些情况下很酷,但在大多数情况下是过度工程!
我解释一下。如何创建静态方法。只需将 "static" 放在方法前面即可。您可以通过调用 Class.Method() 轻松调用它。此外,它对系统来说是高效的,因为该方法只创建一次。
亲:效率高。
缺点:不可变
虽然DI,你可能需要一些容器,然后是一个接口,你可以添加一个class,任何实现接口的class。而且,在代码的某些部分,您将需要创建 class 的实例(因此创建该方法的新实例)。
Pro: 是可变的
缺点:效率不高,冗长。
对于我的 ASP.NET MVC 项目,我曾经严重依赖静态方法来访问数据,有点像这样:
public class MyTable
{
public static IEnumerable<MyTable> findAll()
{
using (var connection = new SqlConnection(Provider.connString))
{
//implementation here
}
return datas;
}
public static MyTable find(guid id)
{
using (var connection = new SqlConnection(Provider.connString))
{
//implementation here
}
}
}
所以我可以在我的控制器中这样调用它们:
var datas = MyTable.findAll();
我对它很满意,但我怀疑我是否在使用它进行数据访问方面做得很好。
现在,我正在尝试将依赖注入应用于我的数据访问 class 只是为了学习目的,就像这样:
public class MyTable
{
public IDatabaseEngine _engine = null;
public MyTable()
{
}
public MyTable(IDatabaseEngine engine)
{
_engine = engine;
}
public IEnumerable<MyTable> findAll()
{
using (var connection = _engine.getConnection())
{
//implementation here
}
return datas;
}
public MyTable find(guid id)
{
using (var connection = _engine.getConnection())
{
//implementation here
}
return data;
}
}
问题是,这意味着我必须创建一个 MyTable
class 的实例来调用我的控制器上的数据访问方法,如下所示:
var table = new MyTable(new MSSQLEngine(provider.connString));
var datas = table.findAll();
好吧,要么是我没有足够的经验来解决这个问题,要么是我做错了,我觉得为我需要的每个数据访问实例化对象感到不舒服。
我的问题是
- 我是不是做错了依赖注入? (我想我是)
- 创建数据访问对象 class 以调用是好的做法吗 控制器或其他 classes? 中的数据访问方法
- 改用静态方法是好的做法吗? (就像我 在第一个例子中做)
- 如果我的 DI 实现是错误的,我该如何纠正?
您问题的答案:
- 没有,详见下文
- DI 的主要优点是依赖于抽象而非实现。您不需要创建 classes 的实例,DI 会为您完成。您只需要将接口注入您的 classes 并在您的 IoC 中注册它们。
- 不,因为您将无法为您的方法编写单元测试。
- 见下文。
要正确使用 DI,首先您需要将 MyTable
class 提取到接口中,然后将该接口注入您的控制器。
public interface IMyTable
{
IEnumerable<MyTable> findAll();
// other methods
}
public class MyTable : IMyTable
{
// your implementation
}
那么你的控制器应该是这样的:
public class YourController : Controller
{
private IMyTable myTable;
public YourController(IMyTable myTable)
{
this.myTable = myTable;
}
public ActionResult YourAction()
{
var result = myTable.findAll();
// ...
}
}
我个人使用 Castle Windsor 作为 IoC 容器,here is an example 在 ASP.NET MVC 应用程序中使用 Castle Windsor
依赖注入只是一种在实例字段中存储依赖项的技术,因此您基本上是在
MyTable
实现中正确执行它。如果您在控制器的构造函数中获得
IDatabaseEngine
的实例,如果您要在控制器的测试中模拟数据库引擎,则可以从依赖注入中受益。您仍然需要一种方法在您的应用程序中 注入 实例。至于现在,您正在控制器中创建一个具体的 classMSSQLEngine
实例,因此没有任何好处。在这种情况下使用静态方法并不好,因为在您决定实施与数据库无关的测试时,您需要重构为使用实例。从最小的测试设置开始是一个很好的做法,这样您就可以在项目生命周期的早期阶段实现可测试性。我建议在你的代码库变大之前完成这个困难的部分。
了解如何在控制器中注入
IDatabaseEngine
的实例,并编写一个利用依赖注入的最小测试。大多数 MVC 框架都允许设置 IoC 容器作为工厂。在测试中,您需要使用一些模拟实现或模拟框架,例如 Moq 来构成IDatabaseEngine
. 的实例
虽然 DI 在某些情况下很酷,但在大多数情况下是过度工程!
我解释一下。如何创建静态方法。只需将 "static" 放在方法前面即可。您可以通过调用 Class.Method() 轻松调用它。此外,它对系统来说是高效的,因为该方法只创建一次。
亲:效率高。 缺点:不可变
虽然DI,你可能需要一些容器,然后是一个接口,你可以添加一个class,任何实现接口的class。而且,在代码的某些部分,您将需要创建 class 的实例(因此创建该方法的新实例)。
Pro: 是可变的 缺点:效率不高,冗长。