带 EF 4 的存储库模式 - 我走在正确的轨道上吗?
因此,在过去的几周里,我一直在努力尝试获得服务/存储库/工作单元的整个模式,我得出了以下结论,并想看看是否有专家认为我走在正确的轨道上。
我正在使用 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
您在这里看到任何缺陷吗?建议?魔法? :)
So I have been beating my head into the wall for the last few weeks trying to get this whole pattern of Service/Repository/UnitOfWork, and I have come to the following conclusions and wanted to see if any experts thought I was on the right track.
I am using Ninject to inject these interfaces into the constructors of each layer.
I am using a RepositoryBase(Of TEntity) that all my specific repositories will derive from and implement their own interface:
Interfaces
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
Repository/UnitOfWork Implementations
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
Service Implementations
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
Any flaws that you see here? Suggestions? MAGIC? :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
好像我每天都在为您回答同一主题的问题。 :)
无论如何 - 关于这个问题 - 我同意@qes。
服务/存储库结合的目的是让您的存储库变得简单,并且由服务提供执行查询的逻辑。您的服务应该具有“消费者”(MVC 应用程序)所需的特定方法,例如:
简单地包装调用是没有意义的。您的服务应该充当 MVC 应用程序和底层存储库之间的外观。
基本上,您的 OrderRepository (例如)定义了对订单的操作。
然后,您的 OrderService 应提供添加/检索/保存/删除订单的所有不同可能方式。
这就是为什么我不喜欢存储库中的“单个”、“第一个”、“全部”方法。
我只有一种“读取”方法,称为“查找”。
然后,该服务应该具有“Single”、“First”、“All”方法,只需使用基本 LINQ 来实现 Find 方法即可。
在我看来,你的存储库过于复杂。
我的 Repository 接口只有 3 个方法:
而我的 Service 接口有 5 到 20 个方法。
Seems like i'm answering a question for you everyday on the same topic. :)
Anyway - onto the question - i agree with @qes.
The point of the Service/Repository marriage is so your Repositories are simple, and it's up to the Service to provide the logic to execute the queries. Your service should have specific methods required for the "consumer" (the MVC app), such as:
Simply wrapping calls is pointless. Your Service should act as a facade between your MVC app and your underlying Repository.
Basically, your OrderRepository (for example), defines operations on Orders.
Your OrderService should then provide all the different possible ways an Order can be added/retrieved/saved/deleted.
Which is why i'm not a fan of the "Single", "First", "All" methods on the Repository.
I only have one "Read" method, called "Find".
The service should then have the "Single", "First", "All" methods, simply using basic LINQ to materialize upon the Find method.
Your Repository is overly complicated IMO.
My Repository interface only has 3 methods:
And my Service interface has anywhere between 5 and 20.
如果 Service 类只有代码传递到存储库,那么它的意义何在?
What is the point of the Service class if it's only code is passing through to the Repository?