存储库和服务,MVC模型

时间:2011-01-26 15:48:57

标签: fluent-nhibernate service asp.net-mvc-3 repository-pattern

所以我一直在学习Repository模型,似乎预计Repositories不会做很多错综复杂的逻辑。但是我也读到大多数业务逻辑不应该在我的Controllers内。那我该把它放在哪里呢?

我查看了一些示例应用程序,似乎他们有另一个名为Services层,它为事物做了更复杂的逻辑。那么这个因素如何影响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 nHibernateASP.NET MVC 3.0Castle.Windsor

我应该做一些类似......

的事情
class MembershipService
{
 private readonly IMembershipRepository membershipRepository;

 public MembershipService(ISession session)
 {
  membershipRepository = new MembershipRepository(session);
 }
}

永远不要让我的控制器直接访问Repositories

2 个答案:

答案 0 :(得分:4)

  

我读到的所有内容都说我应该将我的ISession注入我的存储库。

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

  

这意味着我无法将ISession注入到我的服务中,那么如何从我的服务中进行数据库访问?

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

所以回顾一下:

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

答案 1 :(得分:1)

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

创建像这样的反模式服务。

这样的服务有多少责任?有多少理由可以改变?

此外,如果您将逻辑置于服务中,您将最终陷入贫血领域。您最终将得到的是事务脚本样式中的过程代码。而且我并不是说这一定是坏事。

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

这应该是巨大红旗:

public MembershipCreateStatus Create(string username, string password)
{
  return membershipRepository.Create(username, password);
}

有什么意义?层为图层?该服务在这里没有任何价值,没有任何用处。

缺少很多概念。

首先,考虑使用Factory创建对象:

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类包含可以在实体上执行的每个操作的方法,这似乎对我的感觉非常冒犯。

相反,我尝试通过将每个操作建模为不是单个Service类上的方法,而是作为单独的Command类来更明确和更好地捕获意图。

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);
    }
}

使用与IoC容器接口的简单类调度命令。

这有助于避免整体服务类,并使项目的结构和逻辑位置更加清晰。