【问题标题】:Help using the Repository Pattern?帮助使用存储库模式?
【发布时间】:2011-02-23 04:04:23
【问题描述】:

我正在使用实体框架和使用 T4 模板生成的 POCO。我将生成的类放在一个单独的程序集中。

好的,一个非常简单的例子:

我在模型中有一个 Category 实体,它有 SubCategories(1-Many with SubCategory)。

当我使用以下代码时,我得到 ObjectContext 实例已被释放,不能再用于需要连接的操作。

Public Interface ICategoryRepository
    Inherits IRepository(Of Category)

    Function GetCategories() As IQueryable(Of Category)
    Function GetCategoryByID(ByVal ID As Integer) As Category

End Interface

Public Class CategoryRepository
    Implements ICategoryRepository

    Public Function GetCategories() As System.Linq.IQueryable(Of Business.Category) Implements ICategoryRepository.GetCategories
        Using db As New GTGContainer
            Return db.Categories
        End Using
    End Function

    Public Function GetCategoryByID(ByVal ID As Integer) As Business.Category Implements ICategoryRepository.GetCategoryByID
        Using db As New GTGContainer
            Return db.Categories.FirstOrDefault(Function(x) x.ID = ID)
        End Using
    End Function

End Class

Public Class HomeController
    Inherits System.Web.Mvc.Controller

    Private _CategoryRepository As GTG.Data.Repositories.ICategoryRepository

    Public Sub New()
        Me.New(New GTG.Data.Repositories.CategoryRepository)
    End Sub

    Public Sub New(ByVal Repository As GTG.Data.Repositories.ICategoryRepository)
        _CategoryRepository = Repository
    End Sub

    Function Index() As ActionResult
        Dim m As New HomeViewModel
        m.Categories = _CategoryRepository.GetCategories

        Return View(m)
    End Function

End Class

Public Class HomeViewModel
    Public Property Categories As List(Of GTG.Business.Category)

End Class

任何帮助都会很棒。谢谢!

【问题讨论】:

    标签: asp.net-mvc vb.net entity-framework asp.net-mvc-3 repository-pattern


    【解决方案1】:

    这是因为您的 GetCategories() 返回一个 IQueryable,它实际上不是内存中的集合。当您的 View 尝试枚举它时,它会尝试访问数据库,这显然是做不到的。简单的补救方法是通过在 GetCategories() 中调用 ToList() 将其转换为内存中的集合。即 db.Categories.ToList()。

    【讨论】:

    • @anon - 是的,我试过了,它有效,但是你如何处理儿童收集和延迟加载它们?所以说我想要 SubCategories 关闭 Category 实体?
    • 那么在你枚举之后它就变成了一个内存集合。它从来都不是内存中的集合。
    • 这样做会移除应用服务器端过滤的能力。因此,如果您的类别列表很长并且您不想全部列出,那么这是一个不好的选择。
    • 如果这些是您仅有的层,那么您将需要在您的存储库中调用 ToList()。如果您想要过滤功能(正如 Chris 所提到的),您可以在存储库中使用更专业的方法,或者您可以使用另一个服务层将 IQueryables “扁平化”为内存表示。延迟加载的属性将在该层中被调用。
    • 澄清一下:“Using”语句是在请求数据之前处理数据库连接/上下文。
    【解决方案2】:

    让上下文贯穿存储库的整个生命周期。

    Public Class CategoryRepository
        Implements ICategoryRepository
    
        Private dbContext As GTGContainer
    
        Public Sub New()
            dbContext = New GTGContainer
        End Sub 
    
        Public Function GetCategories() As System.Linq.IQueryable(Of Business.Category) Implements ICategoryRepository.GetCategories
            Return dbContext.Categories
        End Function
    
        Public Function GetCategoryByID(ByVal ID As Integer) As Business.Category Implements ICategoryRepository.GetCategoryByID
            Return dbContext.Categories.FirstOrDefault(Function(x) x.ID = ID)
        End Function
    End Class
    

    【讨论】:

    • 我是否需要担心清理它(Dispose)?我知道 GC 会及时得到它,但这是不好的做法吗?
    • 如果你不小心,这种方法有很多缺点。在她关于实体框架的书中,Julie Lerman 建议对任何返回集合的方法调用 ToList() (books.google.com/…)。另请参阅 ytechie.com/2009/06/…thinkbeforecoding.com/post/2009/01/19/…。在您确定确实需要 IQueryable 之前,我建议您不要使用它。
    • 这是解决更大问题的第一步。 OP 呈现存储库的方式不会走得太远。我的建议是第一步解决这个问题。在一个问题中提出一个企业级存储库解决方案即使不是不可能也非常困难,因为它会涉及其他概念和模式的讨论,如 UoW、IoC 和 DI。将上下文保存在存储库中并没有错。像其他事情一样,这也带来了一些责任。请先查看few results 详细说明。
    • @Sam Striano 和@anon,下一步是根据另一个关于Repository 的问题来管理上下文的生命周期。这不仅适用于生命周期管理,而且当我们有多个存储库并希望在它们之间共享上下文时也是如此。
    猜你喜欢
    • 1970-01-01
    • 2011-11-26
    • 2011-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-27
    • 2014-03-15
    • 1970-01-01
    相关资源
    最近更新 更多