I am using a custom Data Transfer Object framework in my design. As part of this, I am using the repository pattern to retrieve data from a data store. I will have multiple data stores of varying types, so I can’t just depend on Entity Framework for everything. This will mean a lot of extra work setting up repositories, but it will also give me the added benefit of using Dependency Injection for consuming repositories.
Here is my generic DtoRepository interface that my other repository interfaces will implement:
Public Interface IDtoRepository(Of TDto As DtoBase) : Inherits IDisposable Property Session As IUnitOfWork Function GetAll() As IList(Of TDto) Function GetAll(ByVal predicate As Func(Of TDto, Boolean)) As IList(Of TDto) Function Add(ByVal dto As TDto) As String Sub Delete(ByVal id As String) Sub Update(ByVal dto As TDto) End Interface
This blog entry will focus on the GetAll(ByVal predicate As Func(of TDto, Boolean)) method and how I use it in my test repository.
Here is the implementation in my test repository:
Public Function GetAll(predicate As Func(Of Models.TestDto, Boolean)) As IList(Of Models.TestDto) Implements IDtoRepository(Of Models.TestDto).GetAll ' create a temporary list to hold any matches Dim tList As New List(Of TestDto) ' loop through our list of dtos to see if we have a match For Each tempDto In _dtoList ' try to match the incoming query with the temp dto If predicate.Invoke(tempDto) Then ' it matched, so add it to our temporary list tList.Add(tempDto) End If Next ' the following is a short cut for the List. It is here for demo purposes to show how you can reuse the predicate 'Return _dtoList.Where(predicate).ToList() ' return our temporary list containing all matches Return tList End Function
_dtoList is a local variable of List(Of TestDto) that contains the data for the test repository.
The code to look at here is the loop that goes through each of the DTOs in the data list and checks to see if we have a match. It does this by invoking the predicate that was passed in. We could have simply passed the predicate into the Where extension method on the List, but I wanted to demonstrate how you can Invoke a generic function to get the desired results for situations where you cannot pass the predicate into the data store. In the case of Entity Framework, I would simply pass this into the Where for my context.
Here is an example of how this method is being used:
<TestMethod()> _ Public Sub TestGetAllById() Dim testRepository As New TestRepository() Assert.AreEqual("Description2", _ testRepository.GetAll( _ Function(x) x.Id = "9b028687-2fda-4964-af92-836c0a4b13ec") _ .SingleOrDefault() _ .Description) End Sub
As you can see, we use a simple Lambda expression to ask for the DTO with the Id of
Then we make sure that the Description matches what we expected.
Using the generic function in this way allows me to have a more dynamic and generic repository system that I can use with multiple data sources without having to do too much conversion for the ones that support predicates out of the box.