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

Pra*_*bhu 16 .net c# asp.net-mvc entity-framework entity-framework-4

我知道存储库模式上已有很多线程但不知何故我觉得我的问题有点不同.也许是因为昨天我第一次听说POCO这个词.

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

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

Rob*_*nik 33

首先是关于Asp.net MVC项目模板的观察

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

让我们继续回答

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

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

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

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

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

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

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

  • 我不能赞成这个!我已经多次说过确切的事了,我通常会对YAGNI的评论发表评论,或者我很疯狂,这告诉我大多数人只是编写简单的CRUD应用程序而不会从这些想法中受益.这是我不再活跃的主要原因.除了"做MSFT所说的"之外的任何建议都会被大多数人忽略. (3认同)

gid*_*eon 8

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

所以你的项目是QandA

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

public interface IRepository<T>
{
    T Save(T entity);
    void Delete(T entity);
    IQueryable<T> GetAll();
    T GetById(int id);
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以拥有工厂或使用依赖注入来获取实际的存储库.所以:

class QuestionRepo : IRepository<Question>
{
 //call xxxEntites and get/save/delete yourentities here.
}
static class RepositoryFactory
{
 public static IRepository<Question> GetQuestionRepo()
 {
  return new QuestionRepo();
 }
}
Run Code Online (Sandbox Code Playgroud)

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

IRepository<Question> qRepo = RepositoryFactory.GetQuestionRepo();
Question q =  qRepo.GetById(1);
Run Code Online (Sandbox Code Playgroud)

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

static class RepositoryFactory
{
 public static IRepository<Question> GetQuestionRepo()
 {
  return new FakeQuestionRepo();
  //create your own fake repo with some fixed fake data.
 }
}
Run Code Online (Sandbox Code Playgroud)

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

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

class QuestionForm
{
 public string Title
 public string QuestionContent
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

您可能希望看到这些SO问题:
存储库是否应该实现IQueryable <T>?
存储库模式:每个实体的一个存储库类?

我希望它有所帮助.


Phi*_*ilB 5

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

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

您可以拥有单个存储库类或每个实体的存储库.

  • @Jaco Pretorius:问题对象可能有AddAnswer,Close,SelectAnswer等操作,这可能是业务问题.问题对象不会有保存,获取,更新或删除操作,因为这些是持久性问题,并且是存储库的责任.对业务对象没有任何操作会导致一个贫乏的域模型http://en.wikipedia.org/wiki/Anemic_Domain_Model,它通常被认为是反模式. (2认同)