-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnhibernate-integration.html
212 lines (187 loc) · 8.86 KB
/
nhibernate-integration.html
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<title>Entities</title>
<link type="text/css" rel="stylesheet" href="bootstrap.min.css" />
</head>
<body>
<ul>
<li><a href="#DocNugetPackage">Nuget package</a></li>
<li><a href="#DocConfiguration">Configuration</a><ul>
<li><a href="#DocEntityMapping">Entity mapping</a></li>
</ul>
</li>
<li><a href="#DocRepositoryImpl">Repository implementation</a><ul>
<li><a href="#DocDefaultImpl">Custom repositories</a></li>
<li><a href="#DocCustomRepositoryMethods">Custom repositories</a></li>
<li><a href="#DocAppBaseRepo">Application specific base repository class</a></li>
</ul>
</li>
<li><a href="#DocSeeAlso">See also</a></li>
</ul>
<p>ASP.NET Boilerplate can work with any O/RM framework. It has built-in
integration with <strong>NHibernate</strong>. This document will explain how to
use NHibernate with ASP.NET Boilerplate. See also
<a href="http://www.codeproject.com/Articles/768664/Introduction-to-ASP-NET-Boilerplate" target="_blank">
this article</a> for developing a complete application with ASP.NET Boilerplate
and NHibernate. It's assumed that you're already familar with NHibernate in a
basic level.</p>
<h3 id="DocNugetPackage">Nuget package</h3>
<p>Nuget package to use NHibernate as O/RM in ASP.NET Boilerplate is
<a href="http://www.nuget.org/packages/Abp.NHibernate" target="_blank">
Abp.NHibernate</a>. You should add it to your application. It's
better to implement NHibernate in a seperated assembly (dll) in your application
and depend on that package from this assembly.</p>
<h3 id="DocConfiguration">Configuration</h3>
<p>To start using NHibernate, you should first configure it. You should write
configuration code in
<a href="/Pages/Documents/Module-System">PreInitialize</a> of your module.</p>
<pre lang="cs">[DependsOn(typeof(AbpNHibernateModule))]
public class SimpleTaskSystemDataModule : AbpModule
{
public override void PreInitialize()
{
var connStr = ConfigurationManager.ConnectionStrings["Default"].ConnectionString;
Configuration.Modules.AbpNHibernate().FluentConfiguration
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(connStr))
.Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly()));
}
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
}</pre>
<p><strong>AbpNHibernateModule</strong> module provides base functionality and
adapters to make NHibernate work with ASP.NET Boilerplate.</p>
<h4 id="DocEntityMapping">Entity mapping</h4>
<p>In this sample configuration, we're fluently mapping using all mapping
classes in current assembly. An example mapping class can be as shown below:</p>
<pre lang="cs">public class TaskMap : EntityMap<Task>
{
public TaskMap()
: base("TeTasks")
{
References(x => x.AssignedUser).Column("AssignedUserId").LazyLoad();
Map(x => x.Title).Not.Nullable();
Map(x => x.Description).Nullable();
Map(x => x.Priority).CustomType<TaskPriority>().Not.Nullable();
Map(x => x.Privacy).CustomType<TaskPrivacy>().Not.Nullable();
Map(x => x.State).CustomType<TaskState>().Not.Nullable();
}
}</pre>
<p><strong>EntityMap</strong> is a class of ASP.NET Boilerplate that extends
<strong>ClassMap<T></strong>, automatically maps <strong>Id</strong> property and gets <strong>table name</strong> in the constructor. So, I'm deriving from it and mapping other properties
using <a href="http://www.fluentnhibernate.org/" target="_blank">
FluentNHibernate</a>. Surely, you can derive directly from ClassMap. You
can use full API of FluentNHibernate. You can also use other mapping techniques
of NHibernate (like mapping XML files).</p>
<h3>Repository implementation</h3>
<p>You can use default implementation for repositories even without creating a
repository class in your project. Or you can create your repository class
derived from NhRepositoryBase.</p>
<h4 id="#DocDefaultImpl">Default implementation</h4>
<p>You don't have to create repository classes for entities to just use
predefined repository methods. Example:</p>
<pre lang="cs">public class PersonAppService : IPersonAppService
{
private readonly IRepository<Person> _personRepository;
public PersonAppService(IRepository<Person> personRepository)
{
_personRepository = personRepository;
}
public void CreatePerson(CreatePersonInput input)
{
person = new Person { Name = input.Name, EmailAddress = input.EmailAddress };
_personRepository.Insert(person);
}
}</pre>
<p>PersonAppService contructor-injects <strong>IRepository<Person></strong> and
uses the <strong>Insert</strong> method. In this way, you can easily inject
<strong>IRepository<TEntity></strong> (or IRepository<TEntity, TPrimaryKey>) and
use predefined methods. See <a href="/Pages/Documents/Repositories">repository
documentation</a> for list of all predefined methods.</p>
<h4>Custom repositories</h4>
<p>If you want to add some custom method, you should first add it to repository
interface (as a best practice), then implement in the repository class. ASP.NET Boilerplate provides a base class <strong>NhRepositoryBase</strong>
to implement repositories easily. To implement IRepository interface, you can
just derive your repository from this class.</p>
<p>Assume that we have a Task entity that can be assigned to a Person (entity)
and a Task has a State (new, assigned, completed... and so on). We may need to
write a custom method to get list of Tasks with some conditions and with
AssisgnedPerson property pre-fetched in a single database query. See the example
code:</p>
<pre>public interface ITaskRepository : IRepository<Task, long>
{
List<Task> GetAllWithPeople(int? assignedPersonId, TaskState? state);
}
public class TaskRepository : NhRepositoryBase<Task, long>, ITaskRepository
{
public TaskRepository(ISessionProvider sessionProvider)
: base(sessionProvider)
{
}
public List<Task> GetAllWithPeople(int? assignedPersonId, TaskState? state)
{
var query = GetAll();
if (assignedPersonId.HasValue)
{
query = query.Where(task => task.AssignedPerson.Id == assignedPersonId.Value);
}
if (state.HasValue)
{
query = query.Where(task => task.State == state);
}
return query
.OrderByDescending(task => task.CreationTime)
.Fetch(task => task.AssignedPerson)
.ToList();
}
}</pre>
<p><strong>GetAll()</strong> returns <strong>IQueryable<Task></strong>, then we can add some
<strong>Where</strong> filters using given parameters. Finally we can call
<strong>ToList()</strong> to get list of
Tasks.</p>
<p>You can also use <strong>Session </strong>object in repository methods to use
full API of NHibernate.</p>
<p>A repository should get ISessionProvider in it's constructor. In this way, we
can easily inject a fake session provider in unit tests. In runtime, ASP.NET
Boilerplate automatically injects the right session provider.</p>
<h4 id="DocAppBaseRepo">Application specific base repository class</h4>
<p>Although you can derive your repositories from NhRepositoryBase of ASP.NET
Boilerplate, it's a better practice to create your own base class that <strong>extends</strong>
NhRepositoryBase. Thus, you can add shared/common methods to your repositories
easily. Example:</p>
<pre lang="cs">//Base class for all repositories in my application
public abstract class MyRepositoryBase<TEntity, TPrimaryKey> : NhRepositoryBase<TEntity, TPrimaryKey>
where TEntity : class, IEntity<TPrimaryKey>
{
protected MyRepositoryBase(ISessionProvider sessionProvider)
: base(sessionProvider)
{
}
//add common methods for all repositories
}
//A shortcut for entities those have integer Id.
public abstract class MyRepositoryBase<TEntity> : MyRepositoryBase<TEntity, int>
where TEntity : class, IEntity<int>
{
protected MyRepositoryBase(ISessionProvider sessionProvider)
: base(sessionProvider)
{
}
//do not add any method here, add the class above (since this inherits it)
}
public class TaskRepository : MyRepositoryBase<Task>, ITaskRepository
{
public TaskRepository(ISessionProvider sessionProvider)
: base(sessionProvider)
{
}
//Specific methods for task repository
}</pre>
<h3 id="DocSeeAlso">See also</h3>
<p>See <a href="/Pages/Documents/Repositories">repository documentation</a>
for more information on repositories.</p>
</body>
</html>