NHibernate集成
ABP可以使用任何ORM框架,它内置集成NHibernate。此文档将讲解ABP如何使用NHibernate,假定你对NHibernate已经有了一定的了解。
Nuget包
在ABP中实现NHibernate做为ORM框架的Nuget包为Abp.NHibernate。你需要在应用程序中添加它。最好在一个单独的程序集中实现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());
}
}
AbpNHibernateModule模块为使用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<T>的类,它自动映射Id属性并在构造函数中获取表名。所以,我从它继承并使用FluentNHibernate映射其他属性。当然,你可以直接从ClassMap继承,这样就可以使用FluentNHibernate的所有API和NHibernate的其他映射技术(如映射XML文件)。
仓储
仓储用于从高层抽象数据访问。参见仓储文档了解更多。
默认实现
在应用程序中,Abp.NHibernate包为实体实现了默认仓储。所以你不需要为实体创建仓储类就可以使用预定义的仓储方法。示例:
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<Person>并使用了Insert方法。使用这种方式,你可以简单的注入IRepository<TEntity>(或IRepository<TEntity,TPrimaryKey>)并使用预定义的方法。参见仓储文档了解所有的预定义方法。
自定义仓储
如果你想添加一些自定义方法,首先需要添加一个仓储接口(作为最佳实践),然后在一个仓储类中实现它。ABP提供了一个基础类NhRepositoryBase来简单的实现仓储。为了实现IRepository接口,你的仓储类可以仅从这个类继承。
假定我们有一个Task实体,它可以分配给一个Person(实体)并且Task有一个State(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<Task>,然后我们可以使用给定的参数添加一些Where过滤器。最终,我们调用ToList()方法来获取任务列表。
你可以在仓储方法中使用Session对象来使用NHibernate的所有API。
注意:对于分层应用,在domain/core层定义自定义仓储接口,在NHibernate工程中实现它。这样,你就可以在任何工程中注入这个接口而不用引用NH。
应用程序特定基础仓储类
尽管你可以从ABP的NhRepositoryBase类继承你的仓储,但是创建自己的基础类并扩展NhRepositoryBase才是最佳实践。这样,你就可以轻松的在自己的仓储中添加shared/common方法。示例:
//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
}