zoukankan      html  css  js  c++  java
  • 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提供者。

    阅读其他###

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

  • 相关阅读:
    乱谈B2C系统算是今年的总结吧
    浅谈领域模型驱动中表的设计方法
    作业调度小软件
    使用Mutex实现会话状态下单实例运行和系统范围内单实例运行
    几种特殊的类型设计。
    XCommunity权限控制和配置体系
    某个最近不知道为啥很火的小题目的LINQ实现
    C#关于参数为null(空值)的方法调用,重载顺序选择彻底研究
    好吧,不得不说说这篇在首页恶心人的文章
    “九种不够面向对象的对象“的在实际项目中的合理运用
  • 原文地址:https://www.cnblogs.com/farb/p/ABPEntityFramework.html
Copyright © 2011-2022 走看看