ABP理论学习之EntityFramework集成

返回总目录


本篇目录

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并使用仓储中的Insert方法。使用这种方法,你可以轻松地注入 IRepository(或者IRepository<TEntity,TPrimaryKey>),然后使用预定义的方法。所有预定义的方法列表,请查看仓储文档

自定义仓储方法

要实现一个自定义的仓储,只需要从上面创建的仓储基类中派生就可以了。

假设我们有一个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,然后使用给定的参数添加了一些 Where过滤。最后使用 ToList()获得Tasks的列表。

你也可以在仓储方法中使用Context对象到达DbContext,然后可以直接使用EF基础设施了。

仓储应该获得一个IDbContextProvider。这样的话,我们就可以在单元测试中轻松地注入一个伪造的DbContext提供者了。在运行时,ABP会自动地注入正确的DbContext提供者。

阅读其他

你也可以查看仓储文档获取更多关于仓储的知识。

posted @ 2015-12-23 17:22 tkbSimplest 阅读(...) 评论(...) 编辑 收藏