1. 程式人生 > >ABP官方文檔翻譯 9.1 EntityFramework集成

ABP官方文檔翻譯 9.1 EntityFramework集成

喜歡 default complete 不同的 store 返回 特性 主目錄 連接字符串

EntityFramework集成

  • Nuget包
  • DbContext
  • 倉儲
    • 默認倉儲
    • 自定義倉儲
      • 應用特定的基礎倉儲類
      • 自定義倉儲示例
    • 倉儲最佳實踐
  • 事務管理
  • 數據存儲

  ABP可以使用ORM框架,它內置集成EntityFramework。本文檔將講解ABP如何使用EntityFramework。假定你對EntityFramework已經有了初級水平。

Nuget包

  在ABP中使用Abp.EntityFramework nuget包擴展了EntityFramework。需要將它添加到工程中。最好在一個單獨的程序集(dll)中實現EntityFramework並在此程序集中引用Abp.EntityFramework包。

DbContext

  如你所知,為了使用EntityFramework,你需要在應用中定義一個DbContext。一個實例DBContext如下所示:

public class SimpleTaskSystemDbContext : AbpDbContext
{
    public virtual IDbSet<Person> People { get; set; }
    public virtual IDbSet<Task> Tasks { get; set; }

    public SimpleTaskSystemDbContext()
        : 
base("Default") { } public SimpleTaskSystemDbContext(string nameOrConnectionString) : base(nameOrConnectionString) { } public SimpleTaskSystemDbContext(DbConnection existingConnection) : base(existingConnection, false) { }
public SimpleTaskSystemDbContext(DbConnection existingConnection, bool contextOwnsConnection) : base(existingConnection, contextOwnsConnection) { } protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity<Person>().ToTable("StsPeople"); modelBuilder.Entity<Task>().ToTable("StsTasks").HasOptional(t => t.AssignedPerson); } }

  這是一個正規的DbContext類,除此之外它遵循以下規則:

  • AbpDbContext集成而不是DbContext。
  • 需要有構造函數如上面的示例(構造函數參數命名也需要一樣)。說明:
    • 默認構造函數傳遞“Default”到基類作為連接字符串。所以,在web.config/app.config文件中有一個名為“Default”的連接字符串。ABP不使用個這構造函數,但是EF命令行遷移工具和工具命令(如 update-database)使用它。
    • nameOrConnectiongString參數的構造函數,ABP用來在運行時傳遞連接名稱或字符串。
    • existingConnection參數的構造函數用於單元測試,ABP不直接使用。
    • existingConnectioncontxtOwnsConnection的構造函數,當使用DbContextEfTransactionStrategy時(參見下面的事務管理部分),ABP用於單數據庫多dbcontext的場景來共享同一個連接、事務。

  EntityFramework使用常規的方式將類映射到數據庫表。除非自定義了功能,你不需要做任何配置。在這個例子中,我們將實體映射到不同的表。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。從而,你可以在自己的倉儲中添加shared/common方法或重寫已經存在的方法。下面是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。

  默認,對於所有給定DbContext(在這個例子中為SimpleTaskDbContext)的倉儲都使用EfRepositoryBase實現。你可以在你的DbContext中添加AutoRepository特性來使用自己的倉儲基類,如下:

[AutoRepositoryTypes(
    typeof(IRepository<>),
    typeof(IRepository<,>),
    typeof(SimpleTaskSystemEfRepositoryBase<>),
    typeof(SimpleTaskSystemEfRepositoryBase<,>)
)]
public class SimpleTaskSystemDbContext : AbpDbContext
{
    ...
}

自定義倉儲示例

  為了實現自定義倉儲,在你的應用中繼承一個以上我們定義的基礎倉儲類。

  假定,我們有一個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();
    }
}

  我們首先定義了ITaskRepostory接口並實現了它。GetAll()返回IQueryable<Task>,然後我們可以使用給定的參數添加一些Where過濾器。最後我們調用ToList()來獲取Tasks列表。

  你也可以在倉儲方法中使用Context對象引用你自己的DbContext,然後直接使用Entity Framework APIs。

  註意:對於分層應用,在domain/core層定義自定義倉儲接口,在EntityFramework工程中實現它們。從而,你可以在任何工程中註入這個接口而不用引用EF。

倉儲最佳實踐

  • 在可能的地方使用默認倉儲。即使你有一個實體的自定義倉儲(如果你將使用標準的倉儲方法),也可以使用默認的倉儲。
  • 總是為自定義倉儲創建倉儲基類,如上面定義的那樣。
  • 領域層定義自定義倉儲的接口,如果你想將EF從你的domain/application中抽象出來,在EntityFramework工程中自定義倉儲類。

事務管理

  ABP有內置的工作單元系統來管理數據庫連接和事務。Entity Framework有不同的事務管理方式。ABP默認使用TransactionScope方式,但是也有DbContext事務API的內置實現。如果你想切換到DbContext事務API,可以在模塊的PreInitialize方法中配置它:

Configuration.ReplaceService<IEfTransactionStrategy, DbContextEfTransactionStrategy>(DependencyLifeStyle.Transient);

  記住,在代碼中添加"using Abp.Configuration.Startup"以便能使用ReplaceService的泛型擴展方法。

  另外,如在DbContext部分所描述的那樣,你的DbContext需要有構造函數。

數據存儲

  因為ABP內置集成EntityFramework,那麽它就可以使用EntityFramework所支持的數據存儲。我們免費的啟動模板設計為使用Sql Server,但是你可以修改他們以便使用不同的數據存儲。

  例如,如果你想使用MySql,請參見這個文檔

返回主目錄

ABP官方文檔翻譯 9.1 EntityFramework集成