MVC /存储库模式 - 体系结构

时间:2012-11-18 14:12:40

标签: asp.net-mvc-3 nhibernate architecture repository-pattern

我有一个项目,我正在使用NHibernate和ASP.Net MVC。该应用程序旨在允许用户跟踪某些数据,然后根据输入的数据生成统计信息视图。到目前为止,我的应用程序结构看起来像这样:

NHibernate Layer:包含Repository<T>UnitOfWork类,以及实体映射定义。

核心/服务层:包含通用EntityService类。目前,这只是通过IUnitOfWork定义事务范围,并与IRepository接口,以提供更高级别的数据访问服务。

表示层(MVC应用程序):尚未实现,但包含通常的内容和依赖注入。

我有几个问题:

  1. 允许我的MVC应用程序处理所有图层的依赖注入是不是很糟糕的设计?例如,除了将EntityService实例依赖注入控制器之外,它还将处理IRepository类的EntityService依赖注入。服务层应该自己处理,即使这意味着在两个不同的地方执行依赖注入吗?

  2. 我应该在哪里制作统计数据?此业务逻辑似乎不属于我的服务层,目前,该服务层仅包含实体类型定义和用于修改和访问实体属性的接口。我对此有一些想法,但我不确定我最喜欢哪一个:

    • 按原样保留我的服务层并创建一个单独的Statistics项目 - 这完全独立于将要使用它的实体类型,这意味着我的MVC控制器必须在我的业务实体和我之间传递原始数字信息(大概是静态)统计类。这是一个非常简洁的分离,但可能意味着很多业务逻辑仍然存在于表示层中。
    • 创建一个统计项目;但是,在此项目中的类与我的业务实体之间创建紧密耦合。例如,我将传递整个对象(或将它们定义为扩展方法),而不是将Reading对象的传递给方法。这会将业务逻辑从我的MVC应用程序中移出,但紧密耦合似乎有点混乱。
    • 将我的所有业务逻辑保留在服务层中。定义EntityService的强类型子类,因此我的服务包含特定于实体的业务方法和数据存储方法,同时将实体类本身保持为纯数据容器。为任何通用统计处理创建单独的Statistics项目,并通过派生的服务类调用其方法。我的服务类有效地将业务功能与IRepository<T>创建的存储功能合并。
  3. 我对第三种选择犯了错误但是有没有人有任何想法?替代建议?

    提前致谢!

2 个答案:

答案 0 :(得分:3)

初步观察:

我喜欢你描述你的项目的方式,我只是不明白为什么你的数据访问层(DAL)被称为NHibernate层:它是奇怪的,其余的你在其中没有使用技术名称来描述逻辑层(正确)。因此,我建议您将其重命名为DAL,并使用它从NHibernate中抽象出您的应用程序。

我对您的问题的看法:

  1. 绝对没有。将依赖注入应用于所有图层是很好的。一对或有理由的好事:

    1.1 测试:您可以使用另一个DI配置文件模拟DAL接口并使用DAL进行单元测试服务层。以同样的方式,您可以模拟Service for Web Controllers层等等。

    1.2 不同的DAL实现:假设您需要不同的DAL实现(NOSQL,SQL或LINQ而不是NHibernate等)技术,以便为您的项目进行不同的部署或在将来进行扩展。您可以轻松地维护不同的DI配置文件。

  2. 您可以在不同的项目中部署相同的图层。以同样的方式,您可以拥有包含不同图层的项目。我认为他们的关系是正交的:项目描述了一个物理(开发时间和运行时)实现。图层是合乎逻辑的。所以最初我会用第三个选项保持简单。 我只是不明白为什么你对这个选项说出以下内容:

  3.   

    为任何通用统计创建单独的统计项目   处理并通过我的派生服务类调用其方法。我的   服务类有效地将业务功能与存储合并   由IRepository提供的功能。

    我将Statistics视为一个或多个服务,因此您可以将其实现为服务层内的类的命名空间。而且,与任何其他服务一样,您可以注入DAL Repository类。并且,与任何其他Service / DAL一样,Model类可以在不同的Services和DAL类之间共享。


    StatsService.AverageReadingFor(Person p, DateTime start, DateTime end)听起来不错。

    有几种实施方案:

    1. 使用底层存储库功能(例如:SQL avg功能)
    2. 使用可使用依赖注入实现的Observer Pattern
    3. 使用面向方面编程。请参阅Spring.Net chapter作为示例。
    4. 如果您有多个服务层实例(多个服务器)而不是2,则必须使用邮件系统调整3个进程外通信。

答案 1 :(得分:0)

只是一个更新 - 关于我的第二个问题,我决定定义一个IStatsService<T>,希望将IEntityService<T>传递给它的构造函数。我将使用它来进行业务实体的通用统计处理,并创建实现IStatsService<T>的更多接口,我需要更多类型特定的信息。

希望这会帮助那些一直在为类似问题摸不着头脑的人!