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 ...
随机推荐
- 数塔~~dp学习_1
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2084 数塔 Time Limit: 1000/1000 MS (Java/Others) Mem ...
- ubantu下su命令Authentication failure失败的解决方式
Ubuntu安装后,root用户默认是被锁定了的,不允许登录,也不允许 su 到 root . 可以使用: sudo passwd 来重新设置root密码,后即可登陆root. ortonwu@ubu ...
- JXLS 2.4.0系列教程(一)——最简单的模板导出
Java中实现excel根据模板导出数据的方法有很多,一般简单的可以通过操作POI进行.还可以使用一些工具很轻松的实现模板导出.这些工具现在还在维护,而且做得比较好的国内的有easyPOI,国外的就是 ...
- 让BLE设备的名称包含MAC地址
对于研发和测试BLE来说,经常看到同名的设备,是极为不方便的,一大堆设备同时上电会让同事不知道哪一个设备才是自己真正想操作的目标.再说一下小米手环,家中有三支小米手环,打开设备搜索全是“MI”,都不知 ...
- 注意SSIS中的DT_NUMERIC类型转换为字符类型(比如DT_WSTR)时,会截断小数点前的0
我们知道SSIS中有许多数据类型,如下图所示: 但是DT_NUMERIC这个类型有个陷进要注意,我们来做个实验,随便定义一个String类型的SSIS包变量,然后打开该变量表达式窗口: 在变量表达式窗 ...
- CXF之"@XmlType.name 和 @XmlType.namespace 为类分配不同的名称"错误
CXF 的 wsdl2java.bat 生产的代码,拷贝到目录,进行调研 web service接口时,抛出错误: Exception in thread "main" javax ...
- 【shell mysql 导出数据到csv脚本,完美解决乱码转义符等问题】-费元星
#!/bin/bash#@author:feiyuanxing [既然笨到家,就要努力到家]#@date:2017-12-05#@E-Mail:feiyuanxing@gmail.com#@TARGE ...
- java常量池詳解
一.相关概念 什么是常量用final修饰的成员变量表示常量,值一旦给定就无法改变!final修饰的变量有三种:静态变量.实例变量和局部变量,分别表示三种类型的常量. Class文件中的常量池在Clas ...
- Oracle:控制语句 IF..ELSIF语句、CASE语句、FOR循环语句
--多重if语句(注意点:BEGIN END ,IF 条件 THEN,ELSIF 条件 THEN,ELSE... END IF)BEGIN IF FALSE THEN DBMS_OUTPUT.put_ ...
- Vue版本过渡变化
到了2.0以后,有哪些变化: 在每个组件模板,不在支持片段代码 之前: <template id="aaa"> <h3>我是组件</h3>< ...