存储库和服务层之间的区别?

Sam*_*Sam 181 oop asp.net-mvc repository-pattern service-layer

在OOP设计模式中,存储库模式和服务层之间有什么区别?

我正在开发一个ASP.NET MVC 3应用程序,我正在尝试理解这些设计模式,但我的大脑却没有得到它......

Luk*_*Led 317

存储库层为您提供了更多的数据访问抽象级别.而不是写作

var context = new DatabaseContext();
return CreateObjectQuery<Type>().Where(t => t.ID == param).First();
Run Code Online (Sandbox Code Playgroud)

要从数据库中获取单个项目,请使用存储库接口

public interface IRepository<T>
{
    IQueryable<T> List();
    bool Create(T item);
    bool Delete(int id);
    T Get(int id);
    bool SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)

并打电话Get(id).存储库层公开了基本的CRUD操作.

服务层公开使用存储库的业务逻辑.示例服务可能如下所示:

public interface IUserService
{
    User GetByUserName(string userName);
    string GetUserNameByEmail(string email);
    bool EditBasicUserData(User user);
    User GetUserByID(int id);
    bool DeleteUser(int id);
    IQueryable<User> ListUsers();
    bool ChangePassword(string userName, string newPassword);
    bool SendPasswordReminder(string userName);
    bool RegisterNewUser(RegisterNewUserModel model);
}
Run Code Online (Sandbox Code Playgroud)

List()存储库的方法返回所有用户时,ListUsers()IUserService只能返回一个,用户可以访问.

在ASP.NET MVC + EF + SQL SERVER中,我有这种沟通方式:

视图< - 控制器 - >服务层 - >存储库层 - > EF - > SQL Server

服务层 - >存储库层 - > EF此部分在模型上运行.

视图< - 控制器 - >服务层此部分对视图模型进行操作.

编辑:

/ Orders/ByClient/5的流程示例(我们希望查看特定客户的订单):

public class OrderController
{
    private IOrderService _orderService;

    public OrderController(IOrderService orderService)
    {
        _orderService = orderService; // injected by IOC container
    }

    public ActionResult ByClient(int id)
    {
        var model = _orderService.GetByClient(id);
        return View(model); 
    }
}
Run Code Online (Sandbox Code Playgroud)

这是订单服务的界面:

public interface IOrderService
{
    OrdersByClientViewModel GetByClient(int id);
}
Run Code Online (Sandbox Code Playgroud)

此接口返回视图模型:

public class OrdersByClientViewModel
{
     CientViewModel Client { get; set; } //instead of ClientView, in simple project EF Client class could be used
     IEnumerable<OrderViewModel> Orders { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这是接口实现.它使用模型类和存储库来创建视图模型:

public class OrderService : IOrderService
{
     IRepository<Client> _clientRepository;
     public OrderService(IRepository<Client> clientRepository)
     {
         _clientRepository = clientRepository; //injected
     }

     public OrdersByClientViewModel GetByClient(int id)
     {
         return _clientRepository.Get(id).Select(c => 
             new OrdersByClientViewModel 
             {
                 Cient = new ClientViewModel { ...init with values from c...}
                 Orders = c.Orders.Select(o => new OrderViewModel { ...init with values from o...}     
             }
         );
     }
}
Run Code Online (Sandbox Code Playgroud)

  • 为什么要返回服务中的视图模型?如果你有多个客户端(移动/网络),那么假设要模仿的服务不是?如果是这种情况,则viewmodel可能与不同平台不同 (78认同)
  • 同意@Ryan,服务层应该返回实体对象或实体对象的集合(不是IQueryable).然后在ui实体上通过Automapper映射到SomeViewModel. (10认同)
  • @Duffp:您不必为每个实体创建存储库.您可以在IOC库中使用泛型实现并将`IRepository <>`绑定到`GenericRepository <>`.这个答案很老了.我认为最好的解决方案是将所有存储库组合在一个名为"UnitOfWork"的类中.它应该包含每种类型的存储库和一个名为`SaveChanges`的方法.所有存储库应共享一个EF上下文. (5认同)
  • @Sam Striano:如上所示,我的IRepository返回IQueryable.这允许在服务层中添加额外的条件和延迟执行,而不是更晚.是的,我使用一个程序集,但所有这些类都放在不同的名称空间中.没有理由在小项目中创建许多程序集.命名空间和文件夹分离效果很好. (2认同)
  • 而不是从服务层返回viewmodel,你应该返回DTO并使用automapper将其转换为viewModels ..有时它们是相同的,当它们不是你会感谢你已经实现了YGTNI"你要去需要它" (2认同)
  • @LukLed`我认为最好的解决方案是将所有存储库组合在一个名为UnitOfWork的类中.为什么这样做?EF的'DbContext`已经是UOW了. (2认同)

Mik*_*son 40

正如Carnotaurus所说,存储库负责将数据从存储格式映射到业务对象.它应该处理如何从存储器读取和写入数据(删除,更新).

另一方面,服务层的目的是将业务逻辑封装到一个单独的位置,以促进代码重用和关注点的分离.在构建Asp.net MVC站点时,这对我来说通常意味着我拥有这种结构

[控制器]调用[服务器]调用[存储库]

我发现有用的一个原则是在控制器和存储库中将逻辑保持在最低限度.

在控制器中,这是因为它有助于让我保持干爽.我需要在其他地方使用相同的过滤或逻辑,如果我将它放在控制器中,我就无法重复使用它.

在存储库中,这是因为我希望能够在更好的东西出现时替换我的存储(或ORM).如果我在存储库中有逻辑,我需要在更改存储库时重写此逻辑.如果我的存储库只返回IQueryable而另一方面服务执行过滤,我只需要替换映射.

例如,我最近用EF4替换了我的几个Linq-To-Sql存储库,而那些我坚持这个原则的那些存储库可以在几分钟内被替换掉.我有一些逻辑,而不是几个小时.


Cod*_*shi 19

接受的答案(并且投票数百次)有一个重大缺陷.我想在评论中指出这一点,但它会被埋没在30条评论中,所以在这里指出.

我接手了一个以这种方式构建的企业应用程序,我最初的反应是WTH?服务层中的ViewModels?我不想改变惯例,因为多年的发展已经进入它,所以我继续返回ViewModels.当我们开始使用WPF时,它变成了一场噩梦.我们(开发团队)总是说:哪个ViewModel?真正的那个(我们为WPF写的那个)还是服务一个?它们是为Web应用程序编写的,甚至还有IsReadOnly标志来禁用UI中的编辑.主要的,主要的缺陷和所有因为一个词:ViewModel !!

在你犯同样的错误之前,除了上面的故事之外,还有一些原因:

从服务层返回ViewModel是一个巨大的不.这就像说:

  1. 如果您想使用这些服务,最好使用MVVM,这里是您需要使用的ViewModel.哎哟!

  2. 服务正在假设它们将在某个UI中显示.如果由非UI应用程序(如Web服务或Windows服务)使用该怎么办?

  3. 这甚至不是真正的ViewModel.一个真正的ViewModel具有可观察性,命令等.这只是一个名字不好的POCO.(请参阅上面的故事,了解名称的重要性.)

  4. 消费应用程序最好是表示层(ViewModel由此层使用),它更好地理解C#.另一个哎哟!

拜托,不要那样做!

  • 我只是对此发表评论,尽管我知道它并没有增加讨论的内容:“那只是个名字不好的POCO。” &lt;&lt;-在T恤上看起来不错!:) :) (2认同)

Car*_*ode 8

通常使用存储库作为脚手架来填充您的实体 - 服务层将出去并提供请求.您可能会在服务层下放置一个存储库.


小智 6

Repository 层用于访问数据库并帮助扩展对数据库的 CRUD 操作。而服务层由应用程序的业务逻辑组成,并且可以使用存储库层来实现涉及数据库的某些逻辑。在一个应用程序中,最好有一个单独的存储库层和服务层。拥有单独的存储库和服务层使代码更加模块化并使数据库与业务逻辑分离。