ABP文檔 - EntityFramework 集成


文檔目錄

 

本節內容:

 

ABP可使用任何ORM框架,它已經內置了EntityFrame(以下簡稱EF),這個文檔將解釋如何在ABP里使用EF,我們假設你對EF已經有初步的了解。

 

Nuget 包

在ABP里使用EF的Nuget包是Abp.EntityFramework,你應該把它加入到你的應用里,最好在你項目里單獨建立一個EF程序集(dll),然后依賴該於這個包。

 

DbContext

如你所知,要使用EF,應當先為你的應用定義一個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有多個重載,你可以按需要使用它們。

EF可以以一種約定的方式映射類到數據庫表,你甚至不用進行配置,除非你自定義了一些東西,在這個例子里,我們映射實體到不同的表,按默認Task實體映射到Tasks表,但我們把它修改成StsTasks表,也可以用數據注解特性代替配置。我更喜歡使用流暢的配置,你可按喜好選擇。

 

倉儲

倉儲用來抽象來自更高層的數據訪問,查看倉儲文檔獲取更多。

 

默認倉儲

Abp.EntityFramework為所有定義在你的DbContext里的實體,實現了默認的倉儲,你不用創建倉儲類,就可以直接使用預定義的倉儲方法,例如:

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提供了一個基類EfRepositoryBase,可以很容易地實現倉儲。為實現IRepository接口,你的倉儲可以直接繼承該類,但最好是擴展EfRepositoryBase類,你可以在你的倉儲里添加共享/通用的方法。一個SimpleTaskSystem應用的所有倉儲的基類示例:

//Base class for all repositories in my application
public class SimpleTaskSystemRepositoryBase<TEntity, TPrimaryKey> : EfRepositoryBase<SimpleTaskSystemDbContext, TEntity, TPrimaryKey>
    where TEntity : class, IEntity<TPrimaryKey>
{
    public SimpleTaskSystemRepositoryBase(IDbContextProvider<SimpleTaskSystemDbContext> dbContextProvider)
        : base(dbContextProvider)
    {
    }

    //add common methods for all repositories
}

//A shortcut for entities those have integer Id
public class SimpleTaskSystemRepositoryBase<TEntity> : SimpleTaskSystemRepositoryBase<TEntity, int>
    where TEntity : class, IEntity<int>
{
    public SimpleTaskSystemRepositoryBase(IDbContextProvider<SimpleTaskSystemDbContext> dbContextProvider)
        : base(dbContextProvider)
    {
    }

    //do not add any method here, add to the class above (because this class inherits it)

注意:我們從 EfRepositoryBase<SimpleTaskSystemDbContext, TEntity, TPrimaryKey>繼承,這表明在我們倉儲里,ABP使用SimpleTaskSystemDbContext 。

 

自定義倉儲示例

為實現一個自定義倉儲,可以直接繼承你應用里特定的倉儲基類(如我們上面創建的)。

假設我們有一個Task實體,它可以分配給一個Person(實體),並且一個Task有一個State(new,assigned,completed...),我們需要編寫一個自定義方法,通過一些條件和預先獲取的AssisgnedPerson屬性使用一條數據庫查詢,獲取Tasks列表,示例代碼如下:

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<Task>,然后我們使用給定的參數添加一些Where過濾,最后我們可以調用ToList()來獲取Tasks列表。

你可以在你的倉儲方法里使用Context對象,從而直接使用EF的API。

注意:在領域/核心層定義自定義的倉儲接口,在EF所在項目層里實現接口,因此你可以在任何項目里注入這個接口而不用引用EF。

 

倉儲最佳實踐

  • 盡可能使用默認倉儲,即使你有一個某實體的自定義的倉儲,你也可以使用默認倉儲(當使用標准的倉儲方法)。
  • 為你的應用里的自定義倉儲創建一個倉儲基類,如上面那樣定義。
  • 在領域層定義你自定義倉儲的接口(啟動模板里的.Core項目),在EF所在項目里定義自定義倉儲的類。

 

kid1412附:英文原文:http://www.aspnetboilerplate.com/Pages/Documents/EntityFramework-Integration 


免責聲明!

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



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