ABP 基礎設施層——集成 Entity Framework


    本文翻譯自ABP的官方教程《EntityFramework Integration》,地址為:http://aspnetboilerplate.com/Pages/Documents/EntityFramework-Integration

 

    ABP 可以與任何 ORM 框架協同工作,它內置了對 EntityFramework 的集成支持。本文將介紹如何在 ABP 中使用 EntityFramework。本文假定你已經初步掌握了EntityFramework。

    譯者注:怎么才算初步掌握了 EntityFramework 呢?譯者認為應當懂得使用 Code First 模式進行CRUD。

   1 Nuget 包

     要在 ABP 中使用 EntityFramework 作為 ORM 框架的話,需要到 Nuget 上下載一個名為 Abp.EntityFramework 的包。比較好的做法是:新建一個獨立的程序集 (dll),然后在這個程序集中調用這個包和 EntityFramework。

    2 創建 DbContext(Creating DbContext)

    要使用 EntityFramework,首先需要定義一個 DbContext 類。下面是一個DbContex 類的示例:

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); } }

 

     上面的 SimpleTaskSystemDbContext 本質上是一個 DbContext 類,它派生自 AbpDbContext,而不是 DbContext。AbpDbContext 提供了很多重載的構造函數,如果需要的話,我們可以使用它。EntityFramework 可以使用約定的方式來映射實體和數據表。除非你想進行自定義映射,否則你甚至不需要做任何配置。在上例中,我們將實體映射到了不同的表中。默認情況下(按照約定優先於配置的原則,會默認采用約定的方式),Task 實體會映射到 Tasks 表,但在這里我們將它映射到了 StsTasks 表。相比起使用 Data Annotation 模式來進行自定義映射,我更喜歡使用 Fluent API 模式。當然,你可以選擇你所喜歡的模式,這里沒有特別的限制。

3 倉儲(Repositories)

     ABP 提供了一個名為 EfRepositoryBase 的基類,這使得實現倉儲變得簡單快捷。要實現 IRepository 接口,你只需要從這個基類進行派生即可。但是更好的做法是,自定義一個派生自 EfRepositoryBase 的基類,然后在這個基類中添加一些通用的方法。這樣做的好處是,所有派生自這個基類的倉儲都繼承了這些通用方法。

    (1)應用程序專用的倉儲基類(Application specific base repository class)

     在下面的例子中,我們定義了一個名為 SimpleTaskSystem 倉儲基類,這個類是此應用程序所專用的。

// 應用程序中的所有倉儲的基類
public class SimpleTaskSystemRepositoryBase<TEntity, TPrimaryKey> :  EfRepositoryBase<SimpleTaskSystemDbContext, TEntity, TPrimaryKey>     
    where TEntity : class, IEntity<TPrimaryKey> 
{     
  public SimpleTaskSystemRepositoryBase(IDbContextProvider<SimpleTaskSyst  emDbContext> dbContextProvider)
        : base(dbContextProvider)
    {

    }

  //添加倉儲基類的通用方法

}


public class   SimpleTaskSystemRepositoryBase<TEntity> :   SimpleTaskSystemRepositoryBase<TEntity, int>     
where TEntity : class, IEntity<int> {    public SimpleTaskSystemRepositoryBase(IDbContextProvider<SimpleTaskSyst emDbContext> dbContextProvider) : base(dbContextProvider) { }   // 不 要 在 這 里 添 加 任 何 通 用 方 法 ,通 用 方 法 應 當 被添加到 上 面 的 基 類 中(MyRepositoryBase<TEntity, TPrimaryKey>) }

 

     需 要 注 意 的 是 , 我 們 繼 承 了 基 類EfRepositoryBase<SimpleTaskSystemDbContext, TEntity, TPrimaryKey>。這相當於做了一個聲明,它會讓 ABP 在倉儲中調用 SimpleTaskSystemDbContext。

    (2)倉儲實現(Implementing a repository)

      如果你只想使用預定義的倉儲方法的話,你甚至不需要為實體創建倉儲類。如下所示:

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>)對象,然后使用預定義的方法。查看倉儲文檔以獲得預定義方法的列表。

   (3)自定義倉儲(Custom repositories)

    要實現自定義倉儲,只要從上面所創建的應用程序專用的倉儲基類(SimpleTaskSystemRepositoryBase)派生即可。

    假定我們有一個名為 Task 的實體,它可以被賦予 Person 實體。Task 有一個狀態屬性(值為新建、已分配、已完成等)。我們需要編寫一個自定義方法,這個方法能根據某些條件獲取 Task 列表,並且使得 Task 的 AssisgnedPerson 屬性可以在一次數據庫查詢中被加載(使用 EntityFramework 的貪婪加載方法 Include)。如下所示:

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 的接口,緊接着定義了一個名為 TaskRepository 的類來實現它。預定義方法 GetAll()返回了一個 IQueryable<Task> 對象,接着我們將參數放入到 Where 篩選器中,最后調用 ToList()來獲得一個 Task 列表。此外,我們可以通過調用 base.Context 屬性來獲得一個 DbContext 對象,這樣一來,你就可以直接使用 Entity Framework 的所有功能。

    倉儲類應當在構造函數中獲取IDbContextProvider對象。通過這種方式,在單元測試的時候,我們可以很容易地注入一個虛擬的 DbContext Provider 對象;而在運行的時候,ABP 會根據配置注入相應的 DbContext Provider 對象。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM