In this post, i will show how to use generic repository and dependency injection using structuremap. I will be using LINQ to SQL.web
Generic Repositoryapp
The interface for the generic repository is like this:wordpress
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public
interface
IRepository<T> where T :
class
{
void
Create(T entity);
void
Update(T entity);
void
Delete(T entity);
void
Copy(T source, T target);
void
Flush();
T Get(Expression<Func<T,
bool
>> predicate);
IEnumerable<T> GetAll();
System.Data.Linq.Table<T> Table {
get
; }
int
Count(Expression<Func<T,
bool
>> predicate);
IEnumerable<T> Fetch(Expression<Func<T,
bool
>> predicate);
IEnumerable<T> Fetch(Expression<Func<T,
bool
>> predicate, Action<Orderable<T>> order);
IEnumerable<T> Fetch(Expression<Func<T,
bool
>> predicate, Action<Orderable<T>> order,
int
skip,
int
count);
}
|
Now lets go to the implementation of the generic repository interface.post
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
public
class
Repository<T> : IRepository<T> where T :
class
{
protected
IDataContextFactory _dataContextFactory;
public
Repository(IDataContextFactory dataContextFactory)
{
_dataContextFactory = dataContextFactory;
}
public
System.Data.Linq.Table<T> Table
{
get
{
return
_dataContextFactory.Context.GetTable<T>(); }
}
IEnumerable<T> IRepository<T>.GetAll()
{
return
Table.ToReadOnlyCollection();
}
#region IRepository<T> Members
void
IRepository<T>.Create(T entity)
{
Table.InsertOnSubmit(entity);
_dataContextFactory.SaveAll();
}
void
IRepository<T>.Update(T entity)
{
if
(Table.GetOriginalEntityState(entity) ==
null
)
{
Table.Attach(entity);
}
_dataContextFactory.Context.Refresh(System.Data.Linq.RefreshMode.KeepCurrentValues, entity);
_dataContextFactory.SaveAll();
}
void
IRepository<T>.Delete(T entity)
{
Table.DeleteOnSubmit(entity);
_dataContextFactory.SaveAll();
}
T IRepository<T>.Get(Expression<Func<T,
bool
>> predicate)
{
return
Table.FirstOrDefault(predicate);
}
int
IRepository<T>.Count(Expression<Func<T,
bool
>> predicate)
{
return
Table.Count(predicate);
}
public
virtual
IQueryable<T> Fetch(Expression<Func<T,
bool
>> predicate)
{
return
Table.Where(predicate);
}
public
virtual
IQueryable<T> Fetch(Expression<Func<T,
bool
>> predicate, Action<Orderable<T>> order)
{
var orderable =
new
Orderable<T>(Fetch(predicate));
order(orderable);
return
orderable.Queryable;
}
public
virtual
IQueryable<T> Fetch(Expression<Func<T,
bool
>> predicate, Action<Orderable<T>> order,
int
skip,
int
count)
{
return
Fetch(predicate, order).Skip(skip).Take(count);
}
IEnumerable<T> IRepository<T>.Fetch(Expression<Func<T,
bool
>> predicate)
{
return
Fetch(predicate).ToReadOnlyCollection();
}
IEnumerable<T> IRepository<T>.Fetch(Expression<Func<T,
bool
>> predicate, Action<Orderable<T>> order)
{
return
Fetch(predicate, order).ToReadOnlyCollection();
}
IEnumerable<T> IRepository<T>.Fetch(Expression<Func<T,
bool
>> predicate, Action<Orderable<T>> order,
int
skip,
int
count)
{
return
Fetch(predicate, order, skip, count).ToReadOnlyCollection();
}
#endregion
}
|
If you notice ToReadOnlyCollection() this is an extension method of the IEnumerable. This is defined as:this
1
2
3
4
5
6
|
using
System.Collections.ObjectModel;
public
static
IList<T> ToReadOnlyCollection<T>(
this
IEnumerable<T> enumerable)
{
return
new
ReadOnlyCollection<T>(enumerable.ToList());
}
|
I think thats if for our generic repository. To use it, for example if we have a Blog model on our LINQ to SQL we can use the repository like:spa
1
|
IRepository<Blog> BlogRepository =
new
Repository<Blog>();
|
Using StructureMap Dependency Injectorcode
Before reading this, I assume that the reader has knowledge already about dependency injection.orm
First we have to reference the StructureMap DLL. It can be downloaded on the structuremap website.ip
Then we have to create the Registry Class. This class will configure the dependencies. This class should be of type StructureMap.Configuration.DSL.Registryci
The Registry class may look like this:
1
2
3
4
5
6
7
8
|
public
class
ApplicationRegistry : Registry
{
public
ApplicationRegistry()
{
For(
typeof
(IRepository<Blog>)).Use(
typeof
(Repository<Blog>));
For(
typeof
(IDataContextFactory)).Use(
typeof
(DataContext));
}
}
|
After configuring the dependency, we will going to add our Registry to the StructureMap configuration. Usually, this will be on a Bootstrapper class that looks like this:
1
2
3
4
5
6
7
8
9
10
|
public
static
class
Bootstrapper
{
public
static
void
ConfigureStructureMap()
{
ObjectFactory.Initialize(x =>
{
x.AddRegistry(
new
ApplicationRegistry());
});
}
}
|
This code tells the application to use the dependency injection as configure on the registry class. This should be called on program startup, the main method on console application or on global.asax on web application.
1
|
Bootstrapper.ConfigureStructureMap();
|
To get the instance of the repository:
1
|
IRepository<Blog> Repository = ObjectFactory.GetInstance<IRepository<Blog>>();
|
That should be it. Its ready.
If you have questions, please leave comments. I would be happy to answer.
If you want to create test repository that give predictable data, you should have another configuration for your test. Another boot strapper class perhaps but this is for test specific repository configuration. And on your test project call the test boot strapper not the original one.
Or just use mocking for testing like my code below using MOQ:
[TestMethod] public void GetUserByIDTest() { User user = new User() { UserID = 1, UserName = 「mcxiand」, Password = 「password」, }; var userid = 1; //initialize mock var mock = new Mock<IRepository>(); //see if the method in something you have mocked has been called by using Verify(). mock.Setup(x => x.Get(It.IsAny<Expression<Func>>())).Returns(user);
//Initialize Service service = new UserService(mock.Object); //call the method to test var u = service.GetUser(userid);
//Assert Assert.AreEqual(u.UserID, userid, 「not equal」); }
http://mcxiand.wordpress.com/2010/05/13/using-structuremap-di-and-generic-repository/