zoukankan      html  css  js  c++  java
  • ABP官方文档翻译 9.1 EntityFramework集成

    EntityFramework集成

      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,请参见这个文档

    返回主目录

  • 相关阅读:
    ListBox 绑定之-SelectedItem
    tomcat部署web项目的3中方法
    NET 2.0中的字符串比较和方法
    winform WindowsMediaPlayer 属性
    C语言32个关键字解释
    进程间通讯—自定义消息
    常见符号英文表示
    在vs 中运行C程序
    wpf 不是很明白,先记下
    PenTest-log for ging解决方案
  • 原文地址:https://www.cnblogs.com/xajh/p/7143605.html
Copyright © 2011-2022 走看看