Answers:
存储库层为您提供了数据访问之外的更多抽象级别。而不是写
var context = new DatabaseContext();
return CreateObjectQuery<Type>().Where(t => t.ID == param).First();
要从数据库中获取单个项目,请使用存储库界面
public interface IRepository<T>
{
IQueryable<T> List();
bool Create(T item);
bool Delete(int id);
T Get(int id);
bool SaveChanges();
}
并致电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);
}
虽然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);
}
}
这是订单服务的界面:
public interface IOrderService
{
OrdersByClientViewModel GetByClient(int id);
}
该接口返回视图模型:
public class OrdersByClientViewModel
{
CientViewModel Client { get; set; } //instead of ClientView, in simple project EF Client class could be used
IEnumerable<OrderViewModel> Orders { get; set; }
}
这是接口实现。它使用模型类和存储库来创建视图模型:
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...}
}
);
}
}
IRepository<>
到GenericRepository<>
IOC库中。这个答案很老。我认为最好的解决方案是将所有存储库合并为一个类UnitOfWork
。它应该包含每种类型的存储库和一个称为的方法SaveChanges
。所有存储库应共享一个EF上下文。
正如Carnotaurus所说,该存储库负责将您的数据从存储格式映射到业务对象。它应该处理如何读写存储中的数据(也删除,更新)。
另一方面,服务层的目的是将业务逻辑封装到一个地方,以促进代码重用和关注点分离。实际上,在构建Asp.net MVC网站时,这通常对我意味着我拥有这种结构
[Controller]呼叫[Repository]的[Service]
我发现一个有用的原理是将控制器和存储库中的逻辑保持在最低限度。
在控制器中,这是因为它有助于使我保持干燥。我经常需要在其他地方使用相同的过滤或逻辑,如果将其放在控制器中,则无法重用。
在存储库中,这是因为我希望能够在出现更好的情况时更换存储(或ORM)。而且,如果我在存储库中有逻辑,则在更改存储库时需要重写此逻辑。如果我的存储库仅返回IQueryable,而该服务执行过滤,则只需要替换映射即可。
例如,我最近用EF4替换了我的Linq-To-Sql几个存储库,而那些忠于这一原则的存储库可能会在几分钟内被替换。在我有逻辑的地方,要花几个小时。
onBeforeBuildBrowseQuery
并且可以使用查询生成器来更改查询。
公认的答案(并被投票数百次)有一个重大缺陷。我想在评论中指出这一点,但它只会被埋在30条评论中,因此请在此处指出。
我接管了以这种方式构建的企业应用程序,最初的反应是WTH?服务层中的ViewModels?我不想更改约定,因为已经进行了多年的开发,因此我继续返回ViewModels。当我们开始使用WPF时,这变成了一场噩梦。我们(开发人员团队)一直在说:哪个ViewModel?真正的(我们为WPF编写的)还是服务的?它们是为Web应用程序编写的,甚至具有IsReadOnly标志来禁用UI中的编辑。主要,主要缺陷和所有原因都在于一个词:ViewModel!
在您犯同样的错误之前,除了上述我的故事以外,还有其他一些原因:
从服务层返回ViewModel是一个很大的不。这就像在说:
如果要使用这些服务,最好使用MVVM,这是您需要使用的ViewModel。哎哟!
这些服务假设它们将显示在某个地方的UI中。如果非UI应用程序(例如Web服务或Windows服务)使用它怎么办?
那甚至不是真正的ViewModel。真正的ViewModel具有可观察性,命令等。这只是POCO的名称不正确。(有关名称为何重要的信息,请参见上面的我的故事。)
消费应用程序最好是表示层(该层使用ViewModels),并且更好地理解C#。另一个哦!
拜托,不要那样做!
通常,存储库用作填充您的实体的支架-服务层会出去并发出请求。您可能会将存储库放在服务层下。