Fluent nhibernate 存储库和服务,MVC模型

Fluent nhibernate 存储库和服务,MVC模型,fluent-nhibernate,service,asp.net-mvc-3,repository-pattern,Fluent Nhibernate,Service,Asp.net Mvc 3,Repository Pattern,所以我一直在学习关于存储库模型的知识,似乎可以预期存储库不会执行很多复杂的逻辑。然而,我也读到,大多数业务逻辑不应该在我的控制器中。那我把它放在哪里呢 我看了一些示例应用程序,它们似乎有另一个称为服务的层,它为事物提供更复杂的逻辑。那么这个因素是如何融入MVC模式的呢 我是否要构建我的服务以访问我的存储库,然后构建我的控制器以访问我的服务?像这样 interface IMembershipService { bool ValidateUser(string username, string p

所以我一直在学习关于存储库模型的知识,似乎可以预期存储库不会执行很多复杂的逻辑。然而,我也读到,大多数业务逻辑不应该在我的
控制器
中。那我把它放在哪里呢

我看了一些示例应用程序,它们似乎有另一个称为
服务的层,它为事物提供更复杂的逻辑。那么这个因素是如何融入MVC模式的呢

我是否要构建我的服务以访问我的存储库,然后构建我的控制器以访问我的服务?像这样

interface IMembershipService
{
 bool ValidateUser(string username, string password);
 MembershipCreateStatus Create(string username, string password);
}
interface IMembershipRepository
{
 MembershipCreateStatus Create(string username, string password);
}

class MembershipRepository : IMembershipRepository
{
 public MembershipRepository(ISession session)
 {
  **// this is where I am confused...** 
 }
}
class MembershipService : IMembershipService
{
 private readonly IMembershipRepository membershipRepository;
 public MembershipService(IMembershipRepository membershipRepository)
 {
  this.membershipRepository = membershipRepository;
 }

 public bool ValidateUser(string username, string password)
 {
   // validation logic
 }
 public MembershipCreateStatus Create(string username, string password)
 {
  return membershipRepository.Create(username, password);
 }
}

class MembershipController : Controller
{
 private readonly IMembershipService membershipService;

 public MembershipController(IMembershipService membershipService)
 {
  this.membershipService = membershipService
 }
}
代码中标记的部分让我感到困惑。我读到的每一篇文章都说我应该将我的
ISession
注入我的存储库。这意味着我不能将
ISession
注入到我的服务中,那么如何从我的服务中访问数据库呢?我不明白这里的适当流程是什么

当我将
ValidateUser
放入我的
IMembershipRepository
中时,我被告知这是“坏的”。但是
IMembershipRepository
是数据库访问所在的位置。这就是目的,对吗?使数据库访问量保持在最低限度?但是如果我不能把其他的逻辑放进去,那又有什么意义呢

有人能解释一下这一点,给我举个可能更可行的例子吗

我使用的是
Fluent nHibernate
ASP.NET MVC 3.0
,以及
Castle.Windsor

我是不是应该做点像

class MembershipService
{
 private readonly IMembershipRepository membershipRepository;

 public MembershipService(ISession session)
 {
  membershipRepository = new MembershipRepository(session);
 }
}
并且从不让我的控制器直接访问
存储库

我读到的所有东西都说我应该把我的会话注入我的存储库

没错。您需要将会话注入到存储库构造函数中,因为这是进行数据访问的地方

这意味着我不能将ISession注入到我的服务中,那么如何从我的服务中访问数据库呢

在您的服务中不进行数据库访问。该服务依赖于注入其构造函数的一个或多个存储库,并使用它们各自的方法。该服务从不直接查询数据库

因此,总结一下:

  • 存储库包含模型上的简单CRUD操作。这是执行数据访问的地方。这种数据访问并不一定意味着数据库。它将取决于您正在使用的底层存储。例如,您可以调用云上的一些远程服务来执行数据访问
  • 该服务依赖于一个或多个存储库来实现业务操作。此业务操作可能依赖于存储库上的一个或多个CRUD操作。服务甚至不应该知道数据库的存在
  • 控制器使用服务调用业务操作
  • 为了减少不同层之间的耦合,使用接口来抽象操作
我读到的所有东西都说我应该把我的会话注入我的存储库

没错。您需要将会话注入到存储库构造函数中,因为这是进行数据访问的地方

这意味着我不能将ISession注入到我的服务中,那么如何从我的服务中访问数据库呢

在您的服务中不进行数据库访问。该服务依赖于注入其构造函数的一个或多个存储库,并使用它们各自的方法。该服务从不直接查询数据库

因此,总结一下:

  • 存储库包含模型上的简单CRUD操作。这是执行数据访问的地方。这种数据访问并不一定意味着数据库。它将取决于您正在使用的底层存储。例如,您可以调用云上的一些远程服务来执行数据访问
  • 该服务依赖于一个或多个存储库来实现业务操作。此业务操作可能依赖于存储库上的一个或多个CRUD操作。服务甚至不应该知道数据库的存在
  • 控制器使用服务调用业务操作
  • 为了减少不同层之间的耦合,使用接口来抽象操作
创建这样的服务是一种反模式

像这样的服务有多少责任?有多少原因需要改变

同样,如果你把你的逻辑放在服务中,你最终会得到一个贫乏的领域。最终得到的是事务脚本样式中的过程代码。我并不是说这一定不好

也许富域模型不适合您,但这应该是两者之间有意识的决定,而这种多重责任服务在这两种情况下都不合适

这应该是一个巨大的红旗:

public MembershipCreateStatus Create(string username, string password)
{
  return membershipRepository.Create(username, password);
}
重点是什么?为了层而层?这项服务在这里没有任何价值,没有任何用途

缺少很多概念

首先,考虑使用工厂来创建对象:

public interface IMembershipFactory {
    MembershipCreateStatus Create(string username, string password);
}
工厂可以封装用于构建实例或开始实体对象生命周期的任何逻辑

其次,存储库是对象集合的抽象。使用工厂创建对象后,将其添加到对象集合中

var result = _membershipFactory.Create("user", "pw");
if (result.Failed); // do stuff
_membershipRepository.Add(status.NewMembership);  // assumes your status includes the newly created object
最后,
MyEntityService
类包含一个方法,用于对实体执行的每个操作,这对我来说似乎是非常令人讨厌的

相反,我试图通过将每个操作建模为单个命令类,而不是单个服务类上的方法,来更明确、更好地捕获意图

public class ChangePasswordCommand {
    public Guid MembershipId { get; set; }
    public string CurrentPassword { get; set; }
    public string NewPassword { get; set; }
}
然后,在发送此命令时,必须实际执行某些操作,因此我们使用处理程序:

public interface IHandle<TMessageType> {
    void Execute(TMessageType message);
}

public class ChangePasswordCommandHandler : IHandle<ChangePasswordCommand> {

    public ChangePasswordCommandHandler(
         IMembershipRepository repo
      ) 
      {}

    public void Execute(ChangePasswordCommand command) {
      var membership = repo.Get(command.MembershipId);
      membership.ChangePassword(command.NewPassword);
    }
}
公共接口IHandle{
public interface IHandle<TMessageType> {
    void Execute(TMessageType message);
}

public class ChangePasswordCommandHandler : IHandle<ChangePasswordCommand> {

    public ChangePasswordCommandHandler(
         IMembershipRepository repo
      ) 
      {}

    public void Execute(ChangePasswordCommand command) {
      var membership = repo.Get(command.MembershipId);
      membership.ChangePassword(command.NewPassword);
    }
}