【问题标题】:Repository Pattern w/EF 4 - Am I on the right track?带有 EF 4 的存储库模式 - 我在正确的轨道上吗?
【发布时间】:2011-07-13 01:52:26
【问题描述】:

因此,在过去的几周里,我一直在努力尝试了解 Service/Repository/UnitOfWork 的整个模式,我得出了以下结论,并想看看是否有专家认为我在正确的轨道。

我正在使用 Ninject 将这些接口注入到每一层的构造函数中。

我正在使用一个 RepositoryBase(Of TEntity),我的所有特定存储库都将从该库派生并实现它们自己的接口:

接口

Public Interface IUnitOfWork
    Inherits IDisposable

    Sub Commit()

End Interface

Public Interface IRepository(Of TEntity As Class)
    Function Query(Predicate As Expressions.Expression(Of Func(Of TEntity, Boolean))) As IQueryable(Of TEntity)
    Function GetAll() As IEnumerable(Of TEntity)
    Function GetFirst(Predicate As Expressions.Expression(Of Func(Of TEntity, Boolean))) As TEntity
    Function GetSingle(Predicate As Expressions.Expression(Of Func(Of TEntity, Boolean))) As TEntity
    Sub Add(Entity As TEntity)
    Sub Attach(Entity As TEntity)
    Sub Delete(Entity As TEntity)
    Sub Save(Entity As TEntity)

End Interface

Public Interface ICategoryRepository
    Function GetCategories() As IEnumerable(Of Category)
    Function GetCategoryByID(ID As Integer) As Category
    Sub SaveCategory(Category As Category)

End Interface

存储库/UnitOfWork 实现

Public MustInherit Class RepositoryBase(Of TEntity As Class)
    Implements IRepository(Of TEntity)

    Protected Context As GTGContext
    Protected ObjectSet As ObjectSet(Of TEntity)

    Public Sub New(UnitOfWork As IUnitOfWork)
        Context = CType(UnitOfWork, UnitOfWork).Context
        ObjectSet = Context.CreateObjectSet(Of TEntity)()

    End Sub

    Protected Sub Add(Entity As TEntity) Implements Core.Interfaces.IRepository(Of TEntity).Add
        ObjectSet.AddObject(Entity)
    End Sub

    Protected Sub Attach(Entity As TEntity) Implements Core.Interfaces.IRepository(Of TEntity).Attach
        ObjectSet.Attach(Entity)
    End Sub

    Protected Sub Delete(Entity As TEntity) Implements Core.Interfaces.IRepository(Of TEntity).Delete
        ObjectSet.DeleteObject(Entity)
    End Sub

    Protected Function GetAll() As System.Collections.Generic.IEnumerable(Of TEntity) Implements Core.Interfaces.IRepository(Of TEntity).GetAll
        Return ObjectSet.AsEnumerable
    End Function

    Protected Function GetFirst(Predicate As System.Linq.Expressions.Expression(Of System.Func(Of TEntity, Boolean))) As TEntity Implements Core.Interfaces.IRepository(Of TEntity).GetFirst
        Return ObjectSet.First(Predicate)
    End Function

    Protected Function GetSingle(Predicate As System.Linq.Expressions.Expression(Of System.Func(Of TEntity, Boolean))) As TEntity Implements Core.Interfaces.IRepository(Of TEntity).GetSingle
        Return ObjectSet.Single(Predicate)
    End Function

    Protected Function Query(Predicate As System.Linq.Expressions.Expression(Of System.Func(Of TEntity, Boolean))) As System.Linq.IQueryable(Of TEntity) Implements Core.Interfaces.IRepository(Of TEntity).Query
        Return ObjectSet.Where(Predicate)
    End Function

    Protected Sub Save(Entity As TEntity) Implements Core.Interfaces.IRepository(Of TEntity).Save

    End Sub

End Class

Public Class CategoryRepository
    Inherits RepositoryBase(Of Category)
    Implements ICategoryRepository

    Public Sub New(UnitOfWork As IUnitOfWork)
        MyBase.New(UnitOfWork)

    End Sub

    Public Function GetCategories() As System.Collections.Generic.IEnumerable(Of Core.Entities.Category) Implements Core.Interfaces.ICategoryRepository.GetCategories
        'Return GetAll()
        Return Context.Categories.Include("SubCategories").AsEnumerable

    End Function

    Public Function GetCategoryByID(ID As Integer) As Core.Entities.Category Implements Core.Interfaces.ICategoryRepository.GetCategoryByID
        Return GetSingle(Function(x) x.ID = ID)

    End Function

    Public Sub SaveCategory(Category As Core.Entities.Category) Implements Core.Interfaces.ICategoryRepository.SaveCategory
        ObjectSet.First(Function(x) x.ID = Category.ID)
        ObjectSet.ApplyCurrentValues(Category)

    End Sub

End Class

Public Class UnitOfWork
    Implements IUnitOfWork

    Public Property Context As GTGContext

    Public Sub New()
        _Context = New GTGContext

    End Sub

    Public Sub Commit() Implements Core.Interfaces.IUnitOfWork.Commit
        _Context.SaveChanges()

    End Sub

#Region "IDisposable Support"

    Private _IsDisposed As Boolean

    Protected Overridable Sub Dispose(Disposing As Boolean)
        If (Not _IsDisposed) Then
            If (Disposing) Then
                If (_Context IsNot Nothing) Then
                    _Context.Dispose()
                End If
            End If
        End If

        _IsDisposed = True

    End Sub

    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub

#End Region

End Class

服务实现

Public MustInherit Class ServiceBase(Of TEntity As Class)
    Implements IService(Of TEntity)

End Class

Public Class CategoryService
    Inherits ServiceBase(Of Category)
    Implements ICategoryService

    Private Repository As ICategoryRepository

    Public Sub New(Repository As ICategoryRepository)
        Me.Repository = Repository

    End Sub

    Public Function GetCategories() As System.Collections.Generic.IEnumerable(Of Core.Entities.Category) Implements Core.Interfaces.ICategoryService.GetCategories
        Return Repository.GetCategories

    End Function

    Public Function GetCategoryByID(ID As Integer) As Core.Entities.Category Implements Core.Interfaces.ICategoryService.GetCategoryByID
        Return Repository.GetCategoryByID(ID)

    End Function

    Public Sub SaveCategory(Category As Core.Entities.Category) Implements Core.Interfaces.ICategoryService.SaveCategory
        Repository.SaveCategory(Category)

    End Sub

End Class

您在这里看到任何缺陷吗?建议?魔法? :)

【问题讨论】:

    标签: asp.net-mvc entity-framework repository-pattern unit-of-work


    【解决方案1】:

    如果只有代码传递到存储库,Service 类的意义何在?

    【讨论】:

      【解决方案2】:

      好像我每天都在为你回答一个关于同一主题的问题。 :)

      无论如何-关于这个问题-我同意@qes。

      服务/存储库结合的意义在于,您的存储库很简单,由服务提供执行查询的逻辑。您的服务应具有“消费者”(MVC 应用)所需的特定方法,例如:

      public ICollection<Order> FindOrdersForCustomer(int customerId)
      {
         return _orderRepository
            .Query()
            .Where(order => order.CustomerId == customerId)
            .ToList();
      }
      

      简单地包装调用是没有意义的。您的 Service 应该充当 MVC 应用程序和底层存储库之间的外观。

      基本上,您的 OrderRepository(例如)定义了对订单的操作。 然后,您的 OrderService 应提供添加/检索/保存/删除订单的所有不同可能方式。

      这就是为什么我不喜欢存储库中的“Single”、“First”、“All”方法。

      我只有一种“读取”方法,称为“查找”。

      然后,服务应该具有“Single”、“First”、“All”方法,只需使用基本 LINQ 实现 Find 方法。

      您的存储库过于复杂 IMO。

      我的 Repository 接口只有 3 个方法:

      IQueryable<T> Find()
      void Save(T entity)
      void Delete(T entity)
      

      我的服务接口有 5 到 20 个。

      【讨论】:

      • 将这 5-20 个服务功能直接移动到存储库有什么害处吗?似乎一些 IQueryable 不够用的更复杂的查询无论如何都需要放在存储库中,所以为什么不把它全部移到那里呢?
      • @Kevin Pang - 这是一个偏好问题。 DDD 纯粹主义者会同意你的观点,事实上在 DDD 术语中不应该需要“服务”——因为存储库应该抽象域模型并提供所有功能。但是服务/存储库的目标是保持存储库 CRUD 简单且可测试。我宁愿在服务中使用复杂的代码,也不愿在存储库中使用。我可以在服务中使用扩展方法之类的东西来简化代码。到目前为止一直为我工作。正如我所说 - 偏好问题。
      • @RPM1984 - 那么您是使用通用存储库还是特定的每个聚合根目录?
      • @Sam Striano - 两者都有。大多数时候,只需要一个通用存储库,但有时需要一个特定的存储库,它继承自通用。
      • @RPM1984 - 那么你如何保存分离的对象呢?
      猜你喜欢
      • 2023-03-21
      • 1970-01-01
      • 1970-01-01
      • 2014-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-31
      • 2012-03-24
      相关资源
      最近更新 更多