本篇目錄
ABP可以使用任何ORM框架工作,並且已經內置了NHibernate集成。這篇文章會解釋如何在ABP中使用NHibernate。閱讀本文的前提是假設你已經熟悉了EF的基本知識。
Nuget包###
在ABP中使用NH作為ORM的Nuget包是Abp.NHibernate。你應該將它添加到應用程序中。最好在應用程序中分離的程序集(dll)中實現NHibernate,並讓該程序集依賴Abp.NHibernate包。
配置###
要開始使用NHibernate,應該首先要配置它。配置代碼應該寫在模塊的PreInitialize方法中。
[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());
}
}
AbpNHibernate模塊為了使ABP能夠使用NHibernate工作提供了基本的功能和適配器。
實體映射
在下面的樣例配置中,使用了當前程序集中的所有映射類進行了流暢地映射。一個映射類的例子如下所示:
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();
}
}
EntityMap是ABP繼承了 ClassMap
倉儲###
你可以使用倉儲的默認實現而不用在項目中創建倉儲類。或者可以創建派生自NhRepositoryBase的倉儲類。
倉儲基類
雖然可以從ABP的NhRepositoryBase中派生倉儲類,但是最佳實踐是創建自己的繼承了NhRepositoryBase的基類。這樣,我們就可以輕松地將一些公用的方法添加到倉儲中了。例子如下:
//所有倉儲的基類
public abstract class MyRepositoryBase<TEntity, TPrimaryKey> : NhRepositoryBase<TEntity, TPrimaryKey>
where TEntity : class, IEntity<TPrimaryKey>
{
protected MyRepositoryBase(ISessionProvider sessionProvider)
: base(sessionProvider)
{
}
//為所有的倉儲添加一些公共的方法
}
//Id為整數的實體的快捷方式
public abstract class MyRepositoryBase<TEntity> : MyRepositoryBase<TEntity, int>
where TEntity : class, IEntity<int>
{
protected MyRepositoryBase(ISessionProvider sessionProvider)
: base(sessionProvider)
{
}
//不要在這里添加任何方法,在上面的方法中添加(因為該方法繼承了上面的方法)
}
public class TaskRepository : MyRepositoryBase<Task>, ITaskRepository
{
public TaskRepository(ISessionProvider sessionProvider)
: base(sessionProvider)
{
}
//這里添加一些task倉儲特有的方法
}
默認實現
你不需要為實體類創建倉儲,只需要使用預定義的倉儲方法。例子:
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);
}
}
PersonAppService通過構造函數注入了IRepository
自定義倉儲方法
如果你想添加一些自定義的方法,那么首先應該給它添加倉儲接口(這是最佳實踐),然后在倉儲類中實現。ABP提供了一個基類NhRepositoryBase來輕松地實現倉儲。要實現倉儲接口,只需要從倉儲基類中派生倉儲就可以了。
假設我們有一個Task(任務)實體,該任務可以派給一個Person(人)實體,而且Task實體有這么幾種狀態,包括new,assigned,completed等等。我們可能需要寫一個自定義方法來根據一些條件和AssignedPerson來獲取任務的列表。看下面的代碼:
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();
}
}
GetAll()方法返回了IQueryable
你也可以在倉儲方法中使用Session對象來調用NHibernate的全部API。
倉儲應該在它的構造函數中獲得一個ISessionProvider。這樣的話,我們就可以在單元測試中輕松地注入一個偽造的session提供者了。在運行時,ABP會自動地注入正確的session提供者。
閱讀其他###
你也可以查看倉儲文檔獲取更多關於倉儲的知識。