本篇目錄
ABP可以使用任何ORM框架工作,並且已經內置了EntityFramework集成。這篇文章會解釋如何在ABP中使用EntityFramework。閱讀本文的前提是假設你已經熟悉了EF的基本知識。
Nuget包###
在ABP中使用EF作為ORM的Nuget包是Abp.EntityFramework。你應該將它添加到應用程序中。最好在應用程序中分離的程序集(dll)中實現EntityFramework,並讓該程序集依賴Abp.EntityFramework包。
創建DbContext###
要使用EF工作,你應該為應用程序定義一個DbContext。定義DbContext的一個例子如下所示:
public class SimpleTaskSystemDbContext : AbpDbContext
{
public virtual IDbSet<Person> People { get; set; }
public virtual IDbSet<Task> Tasks { get; set; }
public SimpleTaskSystemDbContext()
: base("MyConnectionStringName")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Person>().ToTable("StsPeople");
modelBuilder.Entity<Task>().ToTable("StsTasks").HasOptional(t => t.AssignedPerson);
}
}
除了派生自AbpDbContext而不是DbContext之外,它還是一個常規的DbContext。AbpDbContext的構造函數有很多重載。你可以使用你需要的那個。
EntityFramework可以以一種慣例的方式將類映射到數據庫中對應的表。除非你要做一些自定義的東西,否則你不需要做任何配置。在這個例子中,我們將實體映射到不同的表,默認地,Task實體會映射到Tasks表。但是我們將它改成了StsTasks表,這里沒有用數據注解特性配置,我更喜歡使用流暢的配置。你也可以選擇你喜歡的方式。
倉儲###
ABP提供了一個基類EfRepositoryBase可以輕松地實現倉儲。為了實習IRepository接口,只需要從這個類中派生倉儲就可以了。但是最好創建你自己的繼承了EfRepositoryBase的基類。這樣,你就可以給倉儲輕松地添加一些共享的方法了。
倉儲基類
一個簡單任務系統(SimpleTaskSystem)應用的所有倉儲的基類例子如下所示:
//所有倉儲的基類
public class SimpleTaskSystemRepositoryBase<TEntity, TPrimaryKey> : EfRepositoryBase<SimpleTaskSystemDbContext, TEntity, TPrimaryKey>
where TEntity : class, IEntity<TPrimaryKey>
{
public SimpleTaskSystemRepositoryBase(IDbContextProvider<SimpleTaskSystemDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
//為所有的倉儲添加一些公共的方法
}
//Id為整數的實體的快捷方式
public class SimpleTaskSystemRepositoryBase<TEntity> : SimpleTaskSystemRepositoryBase<TEntity, int>
where TEntity : class, IEntity<int>
{
public SimpleTaskSystemRepositoryBase(IDbContextProvider<SimpleTaskSystemDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
//不要在這里添加任何方法,在上面的方法中添加(因為該方法繼承了上面的方法)
}
注意我們是從EfRepositoryBase<SimpleTaskSystemDbContext, TEntity, TPrimaryKey>繼承的。這就聲明了ABP在倉儲中使用的數據上下文是SimpleTaskSystemDbContext。
默認實現倉儲
你不需要為實體類創建倉儲,只需要使用預定義的倉儲方法。例子:
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
自定義倉儲方法
要實現一個自定義的倉儲,只需要從上面創建的倉儲基類中派生就可以了。
假設我們有一個Task(任務)實體,該任務可以派給一個Person(人)實體,而且Task實體有這么幾種狀態,包括new,assigned,completed等等。我們可能需要寫一個自定義方法來根據一些條件和AssignedPerson來獲取任務的列表。看下面的代碼:
public interface ITaskRepository : IRepository<Task, long>
{
List<Task> GetAllWithPeople(int? assignedPersonId, TaskState? state);
}
public class TaskRepository : SimpleTaskSystemRepositoryBase<Task, long>, ITaskRepository
{
public TaskRepository(IDbContextProvider<SimpleTaskSystemDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
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)
.Include(task => task.AssignedPerson)
.ToList();
}
}
我們首先定義了一個ITaskRepository接口,然后實現了它。GetAll()方法返回了IQueryable
你也可以在倉儲方法中使用Context對象到達DbContext,然后可以直接使用EF基礎設施了。
倉儲應該獲得一個IDbContextProvider。這樣的話,我們就可以在單元測試中輕松地注入一個偽造的DbContext提供者了。在運行時,ABP會自動地注入正確的DbContext提供者。
閱讀其他###
你也可以查看倉儲文檔獲取更多關於倉儲的知識。