ABP官方文档翻译 9.2 Entity Framework Core
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的更多相关文章
- ABP 教程文档 1-1 手把手引进门之 ASP.NET Core & Entity Framework Core(官方教程翻译版 版本3.2.5)
本文是ABP官方文档翻译版,翻译基于 3.2.5 版本 官方文档分四部分 一. 教程文档 二.ABP 框架 三.zero 模块 四.其他(中文翻译资源) 本篇是第一部分的第一篇. 第一部分分三篇 1- ...
- [Abp 源码分析]七、仓储与 Entity Framework Core
0.简介 Abp 框架在其内部实现了仓储模式,并且支持 EF Core 与 Dapper 来进行数据库连接与管理,你可以很方便地通过注入通用仓储来操作你的数据,而不需要你自己来为每一个实体定义单独的仓 ...
- NET Core & Entity Framework Core
ABP 教程文档 1-1 手把手引进门之 ASP.NET Core & Entity Framework Core(官方教程翻译版 版本3.2.5) 本文是ABP官方文档翻译版,翻译基于 ...
- 全球首发免费的MySql for Entity Framework Core
from:http://www.1234.sh/post/pomelo-data-mysql?utm_source=tuicool&utm_medium=referral Source 源代码 ...
- Entity Framework Core 2.0 使用入门
一.前言 Entity Framework(后面简称EF)作为微软家的ORM,自然而然从.NET Framework延续到了.NET Core.以前我也嫌弃EF太重而不去使用它,但是EF Core(E ...
- ABP官方文档翻译 3.8 数据过滤器
数据过滤器 介绍 预定义过滤器 ISoftDelete 何时使用? IMustHaveTenant 何时使用? IMayHaveTenant 何时使用 禁用过滤器 关于using语句 关于多租户 全局 ...
- Entity Framework Core 之数据库迁移
前言 最近打算用.NET Core写一份开源的简易CMS系统,来练练手 所以又去深入研究了一下Entity Framework Core 发现其实有些细节园子里还是很少讲到. 特意整理了几个细节. 正 ...
- 使用Entity Framework Core访问数据库(DB2篇)
前言 上一篇讲了一些EF Core访问Oracle的坑.(感兴趣请移步:使用Entity Framework Core访问数据库(Oracle篇)) 这篇主要讲一下关于EF Core访问DB2的一揽子 ...
- 使用Entity Framework Core访问数据库(Oracle篇)
前言 哇..看看时间 真的很久很久没写博客了 将近一年了. 最近一直在忙各种家中事务和公司的新框架 终于抽出时间来更新一波了. 本篇主要讲一下关于Entity Framework Core访问ora ...
随机推荐
- C++课程设计类作业4
#include <bits/stdc++.h> using namespace std; class xiexin { public: xiexin() { weight=; grade ...
- webpack + babel
webpack设计思想:不区分.png .css .js 等文件,都视为一个模块.通过require导入,loader加载器编译之后打包在一个主js文件里. 优势:减少http请求. 1. webpa ...
- UE4 Xml读写
UE4自带一个XmlParser,可以很方便的实现Xml的读写. 1,在PublicDependencyModuleNames.AddRange中添加XmlParser. 2,include XmlP ...
- Laravel5中使用阿里大于(鱼)发送短信验证码
在做用户注册和个人中心的安全管理时,我实现借助第三方短信平台(阿里大于(鱼))在Laravel框架中进行手机验证的设置:阿里大于,是阿里通信旗下优质便捷的云通信服务平台,整合了三大运营商的通信能力,为 ...
- :nth-child(n)
规定属于其父元素的第二个子元素的每个 p 的背景色: p:nth-child(2) { background:#ff0000; } 1定义和用法 :nth-child(n) 选择器匹配属于其父元素的第 ...
- navicat将多个表导出为一个sql文件
1.shift选中多个表 2右键选择--转储sql文件---结构和数据
- 将js进行到底:node学习笔记2
node重要API之FS--CLI编程初体验 所谓的"fs"就是file system! 当下几乎任何一门编程语言都会提供对文件系统读写的API,比如c语言的open()函数. 而 ...
- J.U.C atomic AtomicInteger解析
很多情况下我们只是需要简单的,高效,线程安全的递增递减方法.注意,这里有三个条件:简单,意味着程序员尽可能少的底层或者实现起来比较简单:高效,意味着耗用资源要少,程序处理速度要快: 线程安全也非常重要 ...
- mysql插入数据后返回自增ID的方法,last_insert_id(),selectkey
mysql插入数据后返回自增ID的方法 mysql和oracle插入的时候有一个很大的区别是,oracle支持序列做id,mysql本身有一个列可以做自增长字段,mysql在插入一条数据后,如何能获得 ...
- winform程序压缩文件上传,服务器端asp.net mvc进行接收解压
期间编程没什么难度,唯一可能忽略导致结果失败是asp.net mvc配置 对于压缩文件大的话,需要配置mvc的最大接收量: <system.web> <httpRuntime ma ...