MVC3通过服务公开存储库功能

时间:2011-06-04 14:49:11

标签: c# asp.net-mvc-3

我一直在玩asp.net MVC3,并一直在努力决定在哪里放置我的业务逻辑。我现在决定使用服务层:

    public class AnimalsService : IAnimalsService
    {
        private readonly IAnimalsRepository _animalsRepository;

        public AnimalsService(IAnimalsRepository animalsRepository)
        {
            _animalsRepository = animalsRepository;
        }
        public IQueryable<Animal> GetFiveLeggedAnimals()
        {
        ...
        }
    }

控制器看起来像这样:

public class AnimalsController : Controller
{        
    private readonly IAnimalsService _animalsService;

    public AnimalsController(IAnimalsService animalsService)
    {
        _animalsService = animalsService;
    }

    public ViewResult ListFiveLeggedAnimals()
    {
        var animals = _animalsService.GetFiveLeggedAnimals();
        return View(animals);
    }
}

我在存储库中有基本的CRUD逻辑(All,Find,UpdateOrInsert,Delete)。如果我想在我的控制器中使用这些CRUD方法:

1)我是否必须在服务中为这些存储库调用创建包装器方法?

2)在存储库中包含GetFiveLeggedAnimals方法和其他业务逻辑对我来说没有意义吗?

3)我可以在AnimalsService中实现IAnimalsRepository接口,然后调用基本方法(我意识到这是可能的,但我认为这是不好的做法)?

3 个答案:

答案 0 :(得分:3)

  

1)我是否必须在服务中为这些存储库调用创建包装器方法?

大多数情况下,是的。通常,您希望为服务层中的域模型提供CRUD。这样,控制器不需要直接使用存储库(事实上,它永远不应该)。您可以在以后添加更复杂的逻辑,而无需更改外部代码。例如,考虑您想要实现新闻源。现在,每当插入一条五足动物时,你想创建一个新闻项目并将其推送给五足动物粉丝。另一个常见的例子是电子邮件通知。

  

2)在存储库中包含GetFiveLeggedAnimals方法和其他业务逻辑对我来说没有意义吗?

业务逻辑应位于服务层域模型对象本身,并且仅在那里。事实上(见3),如果可能的话,我根本不会特别提供IAnimalRepository

例如,在NoSQL环境中,数据库驱动程序几乎一个存储库。另一方面,当使用复杂的ORM映射和存储过程(部分biz逻辑在DB中)时,您实际上没有选择,只提供了解存储过程的显式接口。

如果可能的话,我会选择IRepository<T>并使用查询对象模式。我认为 LINQ 也可以被认为是基于查询对象 / 存储库的模式。

  

3)我可以在AnimalsService中实现IAnimalsRepository接口,然后调用基本方法(我意识到这是可能的,但我认为这是不好的做法)?

要调用 base 方法,您必须从具体实现继承,例如:来自ConcreteAnimalsRepository

此外,如果您的服务直接或间接实现IAnimalsRepository接口,它会使(未经过滤的)CRUD操作可供所有人使用。

我的看法:不要继承,聚合。服务层具有存储库,但它不是存储库本身:服务层处理所有其他应用程序逻辑(权限,通知),并且存储库是一个非常db层周围的薄包装。

作为一个极端的例子,如果禁止直接删除某些内容,并且在插入较新版本的某些内容时只允许该服务使用它,该怎么办?这可以在聚合时轻松构建。

答案 1 :(得分:1)

根据定义,存储库应该是一个类似于通用集合的类,用于抽象数据库交互。它将包含持久性的典型方法,如Get(object id), Add(T), Remove(T),并可能实现IQueryable<T>

该服务看起来像以下代码。

public class AnimalsService : IAnimalsService
{
    private readonly IRepository<Animal> _repository;

    public AnimalsService(IRepository<Animal> repository)
    {
        _repository = repository;
    }

    public IEnumerable<Animal> GetFiveLeggedAnimals()
    {
     // animal specific business logic
    }
}

答案 2 :(得分:0)

我认为在Controller中使用简单的CRUD操作并且在Service类中有一个包装器是不好的,你应该将所有业务逻辑保留在服务层中,而不是在控制器中 例如,您想要创建一个新的Animal 在控制器中你将有方法

查看示例

    // not good design
public ActionResult Create(AnimalInput input)
{
     Animal animal = new Animal { Name = input.Name}; // set the other propreties
    // if you have a CRUD operations in service class you will call
    animalService.UpdateOrInsert(animal);

}
// better disign
public ActionResult Create(AnimalInput input)
{

    animalService.Create(input.Name);

}

在服务类实现中你应该有 按照

public void Create(string name)
  {
    Animal animal = new Animal { Name = input.Name};
   animalRepository.UpdateOrInsert(animal);
  }

用于GetAll或GetFiveLeggedAnimals()等方法;您可以在服务类中使用包装器,我认为没问题。当你在控制器或Service类中编写一些代码时,我总是想给你一些忠诚,请记住你将如何测试这段代码 并且不要忘记SOLID