Entity Framework Core

介绍

  Abp.EntityFrameworkCorenuget包用来集成EntityFramework(EF)Core ORM框架。安装这个包之后,我们需要为AbpEntityFrameworkCoreModule添加DependsOn特性。

DbContext

  EF Core需要定义一个从DbContext继承的类。在ABP中,我们应该从AbpDbContext继承,如下所示:

public class MyDbContext : AbpDbContext
{
public DbSet<Product> Products { get; set; } public MyDbContext(DbContextOptions<MyDbContext> options)
: base(options)
{
}
}

  如上所示,构造函数有一个DbContextOptions<T>的参数。

配置

在Startup类中

  ConfigureServices方法中使用AddAbpDbContext方法,如下所示:

services.AddAbpDbContext<MyDbContext>(options =>
{
options.DbContextOptions.UseSqlServer(options.ConnectionString);
});

  对于非web工程,没有Startup类。在这种情况下,我们在模块中使用Configuration.Modules.AbpEfCore().AddDbContext方法来配置DbContext,如下所示:

Configuration.Modules.AbpEfCore().AddDbContext<MyDbContext>(options =>
{
options.DbContextOptions.UseSqlServer(options.ConnectionString);
});

  我们使用给定的连接字符串并使用Sql Server作为数据库提供者。options.ConnectionString通常为默认的连接字符串(参见下一部分)。但是ABP使用IConnectionStringResolver来决定。所以,这种行为是可以改变的,连接字符串也可以动态决定。无论何时DbContext示例创建时,传递给AddDbContext的action都会执行。所以,你有机会可以根据条件返回不同的连接字符串。

  所以,在什么地方设置默认字符串呢?

在模块PreInitialize方法中

  你可以在模块的PreInitialize方法中设置默认字符串,如下所示:

public class MyEfCoreAppModule : AbpModule
{
public override void PreInitialize()
{
Configuration.DefaultNameOrConnectionString = GetConnectionString("Default");
...
}
}

  这样,你可以定义GetConnectionString方法从一个配置文件中(一般从appsettings.json文件)返回连接字符串。

仓储

  仓储用来从高层抽象数据访问。参见仓储文档了解更多。

默认仓储

  Abp.EntityFrameworkCore为所有定义在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提供了一个基类EfCoreRepositoryBase来简单的实现仓储。为了实现IRepository接口,你可以从这个类继承。但是最好创建自己的基础类并扩展EfRepositoryBase。这样,你可以容易的在自己的仓储中添加shared/common方法。下面为SimpleTaskSystem应用所有仓储的基类示例:

//Base class for all repositories in my application
public class SimpleTaskSystemRepositoryBase<TEntity, TPrimaryKey> : EfCoreRepositoryBase<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)
}

  注意,我们从EfCoreRepositoryBase<SimpleTaskSystemDbContext,TEntity,TPrimaryKey>继承。这表明在我们的仓储中ABP使用SimpleTaskSystemDbContext。

  默认,给定DbContext(在这个例子中为SimpleTaskSystemDbContext)的所有仓储使用EfCoreRepositoryBase实现。你可以通过在DbContext上添加AutoRepositoryTypes特性来使用自己的仓储基类来取代默认的仓储基类。如下所示:

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

自定义仓储示例

  为了实现自定义仓储,需要继承我们上面定义的特定仓储基础类。

  假定,我们有一个Task实体,它可以被分配给一个Person(实体)并且任务有一个状态(new,assigned,completed...等等)。我们需要编写一个自定义方法基于一些条件并基于AssisgnedPerson属性预获取person实体,在一个数据库查询语句中来获取任务列表。参见示例代码:

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对象引用你的DbContext并直接使用Entity Framework APIs。

  注意:对于分层应用,在domain/core层定义自定义仓储接口,在EntityFrameworkCore工程中实现它。这样,你可以从任何工程中注入这个接口而不用引用EFCore。

取代默认仓储

  即使你有一个TaskRepository,如上所示,任何类仍然可以注入IRepository<Task,long>并使用它。大多数情况下这没有什么问题。但是,如果在你的自定义仓储中重写了一个基类方法会怎样呢?比如说在你的自定义仓储中重写了Delete方法在删除时添加一个自定义行为。如果一个类注入IRepository<Task,long>并使用默认仓储删除一个任务,你自定义的行为将不会起作用。为了克服这个问题,你可以使用默认的你喜欢的一个取代你的自定义实现,如下所示:

Configuration.ReplaceService<IRepository<Task, Guid>>(() =>
{
IocManager.IocContainer.Register(
Component.For<IRepository<Task, Guid>, ITaskRepository, TaskRepository>()
.ImplementedBy<TaskRepository>()
.LifestyleTransient()
);
});

  我们为IRepository<Task,Guid>,ITaskRepository和TaskRepository注册TaskRepository。所以,这些中的任何一个都可以被注入并使用TaskRepository。

仓储最佳实践

  • 在任何可能的地方使用默认仓储。即使你已经有一个实体的默认仓储(如果你将使用标准仓储方法)也可以使用默认的仓储。
  • 总是在应用程序中为自定义仓储创建仓储基类,如上定义。
  • 如果你想从domain/application中抽象出EF Core,那么在domain层定义自定义仓储的接口(在启动模板中为.Core工程),在.EntityFrameworkCore工程中定义自定义仓储类。

返回主目录

ABP官方文档翻译 9.2 Entity Framework Core的更多相关文章

  1. ABP 教程文档 1-1 手把手引进门之 ASP.NET Core & Entity Framework Core(官方教程翻译版 版本3.2.5)

    本文是ABP官方文档翻译版,翻译基于 3.2.5 版本 官方文档分四部分 一. 教程文档 二.ABP 框架 三.zero 模块 四.其他(中文翻译资源) 本篇是第一部分的第一篇. 第一部分分三篇 1- ...

  2. [Abp 源码分析]七、仓储与 Entity Framework Core

    0.简介 Abp 框架在其内部实现了仓储模式,并且支持 EF Core 与 Dapper 来进行数据库连接与管理,你可以很方便地通过注入通用仓储来操作你的数据,而不需要你自己来为每一个实体定义单独的仓 ...

  3. NET Core & Entity Framework Core

    ABP 教程文档 1-1 手把手引进门之 ASP.NET Core & Entity Framework Core(官方教程翻译版 版本3.2.5)   本文是ABP官方文档翻译版,翻译基于 ...

  4. 全球首发免费的MySql for Entity Framework Core

    from:http://www.1234.sh/post/pomelo-data-mysql?utm_source=tuicool&utm_medium=referral Source 源代码 ...

  5. Entity Framework Core 2.0 使用入门

    一.前言 Entity Framework(后面简称EF)作为微软家的ORM,自然而然从.NET Framework延续到了.NET Core.以前我也嫌弃EF太重而不去使用它,但是EF Core(E ...

  6. ABP官方文档翻译 3.8 数据过滤器

    数据过滤器 介绍 预定义过滤器 ISoftDelete 何时使用? IMustHaveTenant 何时使用? IMayHaveTenant 何时使用 禁用过滤器 关于using语句 关于多租户 全局 ...

  7. Entity Framework Core 之数据库迁移

    前言 最近打算用.NET Core写一份开源的简易CMS系统,来练练手 所以又去深入研究了一下Entity Framework Core 发现其实有些细节园子里还是很少讲到. 特意整理了几个细节. 正 ...

  8. 使用Entity Framework Core访问数据库(DB2篇)

    前言 上一篇讲了一些EF Core访问Oracle的坑.(感兴趣请移步:使用Entity Framework Core访问数据库(Oracle篇)) 这篇主要讲一下关于EF Core访问DB2的一揽子 ...

  9. 使用Entity Framework Core访问数据库(Oracle篇)

    前言 哇..看看时间 真的很久很久没写博客了 将近一年了. 最近一直在忙各种家中事务和公司的新框架  终于抽出时间来更新一波了. 本篇主要讲一下关于Entity Framework Core访问ora ...

随机推荐

  1. C++课程设计类作业4

    #include <bits/stdc++.h> using namespace std; class xiexin { public: xiexin() { weight=; grade ...

  2. webpack + babel

    webpack设计思想:不区分.png .css .js 等文件,都视为一个模块.通过require导入,loader加载器编译之后打包在一个主js文件里. 优势:减少http请求. 1. webpa ...

  3. UE4 Xml读写

    UE4自带一个XmlParser,可以很方便的实现Xml的读写. 1,在PublicDependencyModuleNames.AddRange中添加XmlParser. 2,include XmlP ...

  4. Laravel5中使用阿里大于(鱼)发送短信验证码

    在做用户注册和个人中心的安全管理时,我实现借助第三方短信平台(阿里大于(鱼))在Laravel框架中进行手机验证的设置:阿里大于,是阿里通信旗下优质便捷的云通信服务平台,整合了三大运营商的通信能力,为 ...

  5. :nth-child(n)

    规定属于其父元素的第二个子元素的每个 p 的背景色: p:nth-child(2) { background:#ff0000; } 1定义和用法 :nth-child(n) 选择器匹配属于其父元素的第 ...

  6. navicat将多个表导出为一个sql文件

    1.shift选中多个表 2右键选择--转储sql文件---结构和数据

  7. 将js进行到底:node学习笔记2

    node重要API之FS--CLI编程初体验 所谓的"fs"就是file system! 当下几乎任何一门编程语言都会提供对文件系统读写的API,比如c语言的open()函数. 而 ...

  8. J.U.C atomic AtomicInteger解析

    很多情况下我们只是需要简单的,高效,线程安全的递增递减方法.注意,这里有三个条件:简单,意味着程序员尽可能少的底层或者实现起来比较简单:高效,意味着耗用资源要少,程序处理速度要快: 线程安全也非常重要 ...

  9. mysql插入数据后返回自增ID的方法,last_insert_id(),selectkey

    mysql插入数据后返回自增ID的方法 mysql和oracle插入的时候有一个很大的区别是,oracle支持序列做id,mysql本身有一个列可以做自增长字段,mysql在插入一条数据后,如何能获得 ...

  10. winform程序压缩文件上传,服务器端asp.net mvc进行接收解压

    期间编程没什么难度,唯一可能忽略导致结果失败是asp.net  mvc配置 对于压缩文件大的话,需要配置mvc的最大接收量: <system.web> <httpRuntime ma ...