在实践中,上下文(实体框架)应用于控制器或另一抽象层



我目前正在用C#学习.Net MVC。我很好奇人们是如何使用实体框架上下文的。下面列出了几个相关问题。我希望你能提供反馈。

  1. 应该在控制器中实例化上下文吗?在模型中?在另一层抽象中?什么是合适的封装?

  2. 在执行简单的CRUD操作时,是否应该在控制器中调用say context.Add(实体)?

  3. 当创建对上下文的查询时,这些查询是否应该在控制器中完成?还是在模型中?如果在模型中使用这些方法,是否应该使用静态方法?

我希望我的问题很清楚。一般来说,我感兴趣的是应该如何与数据库交互,以及如何从应用程序中正确地提取数据库。欢迎任何与此相关的信息或建议。

这一切都取决于应用程序的大小。但对于大型应用程序,通常不会在控制器中实例化任何依赖项。它使您的代码与某些特定的数据访问提供程序实现紧密耦合。如果你明天要转到MongoDB怎么办?考虑一下你的申请中需要更改的地方。

当您对控制器进行单元测试时,数据访问提供程序的模拟也是如此。您应该能够通过一些模拟的实现来切换真实对象,从而在应用程序中实现持久性。如果您将使控制器依赖于上下文,并且在控制器中实例化上下文,那么这将是不可能的(或者至少非常困难)。

传统方法如下:

  • 创建数据访问抽象,您的控制器将依赖于此。通常存储库就是这样的抽象
  • 并使用一些依赖注入框架将这种抽象的实现注入到控制器中

因此,您的控制器将只知道抽象,更改数据访问提供程序将很容易(只需为MongoDB创建存储库并将该实现提供给控制器),当您对控制器进行单元测试时,也很容易给出数据访问提供方的模拟实现。

样品:

public class SalesController : Controller
{
    private IOrderRepository _repository; // depend on interface
    // inject some implementation of dependency into controller
    public SalesController(IOrderRepository repository)
    {
       _repository = repository;
    }
    public ActionResult Index()
    {
        var orders = _repository.FindAll();
        return View(orders);
    }
}

您将使用具体存储库实现的唯一地方是依赖注入框架的配置,更改实现非常容易:

Bind<DbContext>().To<ShopEntities>();
Bind<IOrderRepository>().To<EFOrderRepository>();

此外,进行单元测试也非常容易:

[Test]
public void ShoulReturnAllOrders()
{
    List<Order> orders = CreateListOfOrders();
    var mock = new Mock<IOrderRepository>();
    mock.Setup(r => r.FindAll()).Returns(orders);
    var controller = new SalesController(mock.Object);
    var result = (ViewResult)controller.Index();
    mock.VerifyAll();
    Assert.That(result.Model, Is.EqualTo(orders));
}

要获得适当的抽象级别,必须定义一个接口。例如:IDataBaseService其中定义了所有必需的操作。例如:嗯.

IEnumerable<BugItem> ReadAllBugs();
IEnumerable<BugItem> ReadAllBugsForProject(string project name); 

等等。。。

然后,您可以使用任何ioc容器,在运行时注入IDataBaseService的实现。

并且控制器将使用IDataBaseService接口而不是DB上下文。

附言:有时候这样的抽象水平有点过头了。这取决于应用程序。

  1. 在控制器中使用IDataBaseService是可以的
  2. 请参阅上一页。不会有这样的电话。您必须定义UpdateBugItemForProject方法
  3. 与以前相同

这是我不久前研究的一个主题。最后,我认为在分离层做这些事情要好得多。

  1. 我们在控制器中创建上下文,然后将其传递给控制器使用的其他层。

  2. 在最简单的场景中,有人可能会说,如果你只添加实体,那就可以了。但如果你有某种验证呢?我的意思不是字段值,比如-如果用户名已经被占用,你就不能添加新用户。如果你把context.Add(entity)方法放在控制器中,那么很快你就会看到控制器方法有100多行代码,它们进行逻辑、验证等

  3. 由于我们的查询非常复杂,所以我们有"queries"命名空间,每个查询包含一个类。此处对此进行了描述。我不太理解你用静态方法提出的问题。

你必须记住,控制器中的所有代码都将很难进行单元测试-你必须设置一些上下文等等。在我的文章中,"瘦控制器,thich模型"模式是ASP.NET MVC中除了展示应用程序之外的所有应用程序都必须具备的模式。

此外,这一切都取决于你的"模型"层是什么。您使用的是ViewModels,还是封装所有逻辑的Models?

最新更新