存储库模式,POCO和业务实体

我知道存储库模式上已经存在很multithreading,但不知怎的,我觉得我的问题有点不同。 也许是因为昨天是我第一次听说POCO这个词。

我的问题是 – 通常,我在我的业务实体中添加和保存方法。 假设我正在编写Q / A网站,并且我有以下实体:问题,答案和评论。 如果我想使用存储库模式,我基本上只需要保留业务实体中的属性(例如,问题),并将我的操作移动到存储库类(例如,QuestionRepository),对吧? 如果这是真的,那么POCO是指具有属性的商业实体吗?

我正在使用Entity Framework 4.0,后者在edmx代码中创建了我的实体。 如果我想使用存储库模式,那么就不需要编写我自己的业务实体(问题,答案等),因为它们已经由EF生成了,对吧? 我需要的只是存储库来做CRUD? 我将为这个例子提供三个存储库,每个实体一个存储库?

您的POCO对象仍然会有操作方法,但这些操作与实体的业务问题有关,而不是持久性问题(CRUD)。 如果您的企业没有业务运营,那么他们将只是财产。

如果要生成它们,则不需要从头开始编写pocos,但是您可能希望使用部分类来扩展它们以用于业务操作和非持久性或计算属性。

您可以为每个实体创建一个存储库类或存储库。

首先观察一下Asp.net MVC项目模板

我必须说,Visual Studio的Asp.net MVC项目模板存在一个小小的误解。 这就是Model文件夹。 不了解MVC模式的人会自动将其与数据模型相关联,而不是与MVC应用程序/表示模型相关联。 这对于简单的应用程序来说很好,我们不区分这两者而不是其他任何东西。

让我们继续回答

当我编写业务级应用程序时,我将我的解决方案分成4个项目(至少):

  • 表示层 – Asp.net MVC应用程序,但我删除了Model文件夹,并将我的所有视图作为强类型视图,以尽可能避免魔术字符串
  • 服务层 – 业务逻辑流程
  • 数据层 – 数据模型即。 EF4 访问此模型的存储库
  • 对象层 – 该项目实际上具有用于层间通信的POCO和各层使用的任何接口(想想IoC)

我的请求过程通常看起来非常干净并以这种方式工作:

  1. 当发出请求时,我的Asp.net MVC控制器操作validation数据(POCO对象),在调用服务之前执行表示层所需的任何操作。
  2. 调用服务来执行业务流程逻辑所需的任何操作,并且通常调用存储库来执行数据操作。
  3. 存储库操纵数据模型中的数据,然后从将返回到服务层的结果创建POCO。
  4. 服务层接收POCO会根据需要执行其他逻辑并将它们返回到演示文稿。
  5. Presentation(控制器)决定显示哪个视图并为该特定视图提供模型并返回它。 当然,代替视图,它也可以是任何其他结果。

在Objects项目中使用单独的MVC模型类(由于循环项目引用而无法将它们放在Model文件夹中)的优点是我可以使用表示优化的类。 或者更好地说: 我有业务流程中心接口而不是以数据为中心。

让我们用一个例子解释一下:例如用户注册视图。 它不能强类型化为数据模型的User实体。 为什么? 因为它有两个密码输入。 所以我可以拥有一个名为UserRegistration的应用程序/表示模型类,即使在数据模型中没有类似的东西。 与数据模型的User实体相比,它的validation工作完全不同。 如果我在没有强类型的情况下完成用户注册,我必须使用每个字段的所有参数来执行控制器操作。 这些不会自动validation,这意味着我可以有更大的bug表面。 有人可能会急于编写代码但忘记validation的某些方面。

在服务器上返回强类型的强类型视图是摆脱用户通常发现的各种模糊错误的最安全方法,特别是如果您不对项目进行任何有条不紊的测试(介于75-90%之间)机会)。

不久之前我和OP在一个非常相似的地方,所以我将在学习了存储库模式之后,通过一些代码来解释我是如何构建我的asp.net mvc应用程序的。

所以你的项目是QandA

您将拥有一个名为QandA.data类库项目,您可以在此处创建edmx文件和所有entity framework类。 然后你有一个每个实体的存储库,如下所示:

 public interface IRepository { T Save(T entity); void Delete(T entity); IQueryable GetAll(); T GetById(int id); } 

然后,您可以拥有工厂或使用dependency injection来获取实际的存储库。 所以:

 class QuestionRepo : IRepository { //call xxxEntites and get/save/delete yourentities here. } static class RepositoryFactory { public static IRepository GetQuestionRepo() { return new QuestionRepo(); } } 

然后在你的调用代码中(在你的asp.net项目中)

 IRepository qRepo = RepositoryFactory.GetQuestionRepo(); Question q = qRepo.GetById(1); 

现在执行上述操作的优点是,您的调用代码不知道实体是如何通过的,因此您可以创建一个模拟存储库来测试您的应用程序。

 static class RepositoryFactory { public static IRepository GetQuestionRepo() { return new FakeQuestionRepo(); //create your own fake repo with some fixed fake data. } } 

现在你调用代码根本不会改变,如果你把它扔成假的或真实的存储库。

此外,罗伯特在他的问题中谈到的是ViewModel。 因此,您不会创建类型为Question的强类型页面。 所以你有了

 class QuestionForm { public string Title public string QuestionContent } 

您的页面将是QuestionForm类型,但在您的创建控制器中,您将从问题表单中获取数据,将其填入您的Question实体,然后通过存储库发送。

 [HttpPost] public ActionResult Create(QuestionForm quesfrm) { IRepository qRepo = RepositoryFactory.GetQuestionRepo(); Question ques = new Question { AskedDate = DateTime.Now, Title = quesfrm.Title, Content = QuestionContent } qRepo.Save(ques); } 

罗伯特提到了为什么要这样做的原因之一,还有其他一些原因,你可以在SO上阅读更多有关视图模型的内容。 另请查看nerddinner的代码

您可能希望看到以下SO问题:
存储库应该实现IQueryable 吗?
存储库模式:每个实体的一个存储库类?

我希望它有所帮助。