文檔目錄
本節内容:
- Nuget 包
- DbContext
- 倉儲
- 預設倉儲
- 自定義倉儲
- 特定的倉儲基類
- 自定義倉儲示例
- 倉儲最佳實踐
ABP可使用任何ORM架構,它已經内置了EntityFrame(以下簡稱EF),這個文檔将解釋如何在ABP裡使用EF,我們假設你對EF已經有初步的了解。
在ABP裡使用EF的Nuget包是Abp.EntityFramework,你應該把它加入到你的應用裡,最好在你項目裡單獨建立一個EF程式集(dll),然後依賴該于這個包。
如你所知,要使用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
kid1412聲明:轉載請把此段聲明完整地置于文章頁面明顯處,并保留個人在部落格園的連結:http://www.cnblogs.com/kid1412/(可點選跳轉)。
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);
}
}
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);
}
}
//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)
}
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();
}
}