ASP.NET Core中使用GraphQL - 第六章 使用EF Core作为持久化仓储
ASP.NET Core中使用GraphQL
- ASP.NET Core中使用GraphQL - 第一章 Hello World
- ASP.NET Core中使用GraphQL - 第二章 中间件
- ASP.NET Core中使用GraphQL - 第三章 依赖注入
- ASP.NET Core中使用GraphQL - 第四章 GrahpiQL
- ASP.NET Core中使用GraphQL - 第五章 字段, 参数, 变量
本篇中我将演示如何配置持久化仓储,这里原文中是使用的Postgres
, 这里我改用了EF Core For SqlServer
。本文的例子需要在上一篇的代码基础上修改。没有代码的同学,可以去https://github.com/lamondlu/GraphQL_Blogs/tree/master/Part%20V下载。
之前我们编写了一个DataStore
类,里面硬编码了一个数据集合,这里我们希望改用依赖注入的方式进行解耦,所以首先我们需要创建一个抽象接口IDataStore
。
public interface IDataStore
{
IEnumerable<Item> GetItems();
Item GetItemByBarcode(string barcode);
}
由于接下来我们需要使用EF Core
, 所以这里我们需要添加一个EF Core
的上下文类ApplicationDbContext
。
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
public DbSet<Item> Items { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Item>().ToTable("Items");
modelBuilder.Entity<Item>().HasKey(p => p.Barcode);
modelBuilder.Entity<Item>().HasData(new Item {
Barcode = "123",
Title = "Headphone",
SellingPrice = 50 });
modelBuilder.Entity<Item>().HasData(new Item {
Barcode = "456",
Title = "Keyboard",
SellingPrice = 40 });
modelBuilder.Entity<Item>().HasData(new Item {
Barcode = "789",
Title = "Monitor",
SellingPrice = 100 });
base.OnModelCreating(modelBuilder);
}
}
这里为了导入一些初始数据,我们在OnModelCreating
方法中使用HasData
方法添加了3个初始数据。
下面我们修改DataStore
类, DataStore
应该实现IDataStore
接口, 其中的GetItemByBarcode
和GetItems
方法需要改为从数据库中读取。
public class DataStore : IDataStore
{
private ApplicationDbContext _applicationDbContext;
public DataStore(ApplicationDbContext applicationDbContext)
{
_applicationDbContext = applicationDbContext;
}
public Item GetItemByBarcode(string barcode)
{
return _applicationDbContext.Items.First(i => i.Barcode.Equals(barcode));
}
public IEnumerable<Item> GetItems()
{
return _applicationDbContext.Items;
}
}
接下来,我们要在Startup.cs
类中的ConfigureServices
添加Entity Framework配置
services.AddDbContext<ApplicationDbContext>(option =>
{
option.UseSqlServer(Configuration.GetConnectionString("SampleDB"));
});
TIPS: 这里注意不要忘记创建一个
appsettings.json
, 在其中添加数据库连接字符串
配置完成之后,我们需要使用以下命令添加Migration,并更新数据库
dotnet ef migrations add Initial
dotnet ef database update
现在针对数据库的修改都已经完成了。
另外我们还需要修改服务注册代码,将注册服务的生命周期从单例(Singleton)改为作用域(Scoped), 因为当注入服务的生命周期为单例时,需要处理多线程问题和潜在的内存泄漏问题。
services.AddScoped<IDataStore, DataStore>();
services.AddScoped<HelloWorldQuery>();
services.AddScoped<ISchema, HelloWorldSchema>();
修改完成后,Startup.cs
最终代码如下:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(option =>
{
option.UseSqlServer(Configuration.GetConnectionString("SampleDB"));
});
services.AddSingleton<IDocumentExecuter, DocumentExecuter>();
services.AddSingleton<IDocumentWriter, DocumentWriter>();
services.AddScoped<IDataStore, DataStore>();
services.AddScoped<HelloWorldQuery>();
services.AddScoped<ISchema, HelloWorldSchema>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseMiddleware<GraphQLMiddleware>();
}
}
现在我们启动项目, 程序会抛出一个错误
System.InvalidOperationException: Cannot resolve scoped service 'GraphQL.Types.ISchema' from root provider
这个问题的原因是,中间件是单例的,如果在中间件的构造函数中使用作用域(Scoped)的依赖注入, 会导致这个问题(具体请参见https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.1)。这里ISchema
的生命周期是作用域,并且在GraphQLMiddleware
类中是从构造函数注入的,所以这里我们需要修改GraphQLMiddleware
类,ISchema
需要改从Invoke
方法注入。
中间件最终代码如下:
public class GraphQLMiddleware
{
private readonly RequestDelegate _next;
private readonly IDocumentWriter _writer;
private readonly IDocumentExecuter _executor;
public GraphQLMiddleware(RequestDelegate next, IDocumentWriter writer, IDocumentExecuter executor)
{
_next = next;
_writer = writer;
_executor = executor;
}
public async Task InvokeAsync(HttpContext httpContext, ISchema schema)
{
if (httpContext.Request.Path.StartsWithSegments("/api/graphql")
&& string.Equals(httpContext.Request.Method,
"POST",
StringComparison.OrdinalIgnoreCase))
{
string body;
using (var streamReader = new StreamReader(httpContext.Request.Body))
{
body = await streamReader.ReadToEndAsync();
var request = JsonConvert.DeserializeObject<GraphQLRequest>(body);
var result = await _executor.ExecuteAsync(doc =>
{
doc.Schema = schema;
doc.Query = request.Query;
doc.Inputs = request.Variables.ToInputs();
}).ConfigureAwait(false);
var json = await _writer.WriteToStringAsync(result);
await httpContext.Response.WriteAsync(json);
}
}
else
{
await _next(httpContext);
}
}
}
修改完成之后,我们重新启动项目,项目正常启动成功, GraphiQL
界面出现。
现在我们还是使用上一章的查询代码,查询二维码是123的货物数据。
数据正常从数据库中读取成功。下一章我们将讲解在ASP.NET Core中如何使用GraphQL添加修改数据。
本文源代码: https://github.com/lamondlu/GraphQL_Blogs/tree/master/Part%20VI
ASP.NET Core中使用GraphQL - 第六章 使用EF Core作为持久化仓储的更多相关文章
- ASP.NET Core中使用GraphQL - 第七章 Mutation
ASP.NET Core中使用GraphQL - 目录 ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间 ...
- ASP.NET Core中使用GraphQL - 第四章 GraphiQL
ASP.NET Core中使用GraphQL ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间件 ASP ...
- ASP.NET Core中使用GraphQL - 第五章 字段, 参数, 变量
ASP.NET Core中使用GraphQL ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间件 ASP ...
- ASP.NET Core中使用GraphQL - 第三章 依赖注入
ASP.NET Core中使用GraphQL ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间件 SOL ...
- ASP.NET Core中使用GraphQL - 最终章 Data Loader
ASP.NET Core中使用GraphQL - 目录 ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间 ...
- ASP.NET Core中使用GraphQL - 第八章 在GraphQL中处理一对多关系
ASP.NET Core中使用GraphQL - 目录 ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间 ...
- ASP.NET Core中使用GraphQL - 第九章 在GraphQL中处理多对多关系
ASP.NET Core中使用GraphQL ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间件 ASP ...
- ASP.NET Core中使用GraphQL - 第一章 Hello World
前言 你是否已经厌倦了REST风格的API? 让我们来聊一下GraphQL. GraphQL提供了一种声明式的方式从服务器拉取数据.你可以从GraphQL官网中了解到GraphQL的所有优点.在这一系 ...
- ASP.NET Core中使用GraphQL - 第二章 中间件
前文:ASP.NET Core中使用GraphQL - 第一章 Hello World 中间件 如果你熟悉ASP.NET Core的中间件,你可能会注意到之前的博客中我们已经使用了一个中间件, app ...
随机推荐
- Python set() 函数
描述 set() 函数创建一个无序不重复元素集,可进行关系测试,删除重复数据,还可以计算交集.差集.并集等. 语法 set 语法: class set([iterable]) 参数说明: iterab ...
- [爬虫]BeautifulSoup4
1.Beautiful Soup的简介 Beautiful Soup是python的一个库,最主要的功能是从网页抓取数据.官方解释如下: Beautiful Soup提供一些简单的.python式的函 ...
- 【BZOJ 1002】: [FJOI2007]轮状病毒
题目大意:(略) 题解: 第一眼,这不是矩阵树裸体,看了看样例,心想3就有16,那100岂不是要上天…… 果然炸long long……emmmm该不会要打高精除吧……害怕,按照老师的话,不可能考高精除 ...
- BZOJ_3687_简单题_bitset
BZOJ_3687_简单题_bitset Description 小呆开始研究集合论了,他提出了关于一个数集四个问题: 1.子集的异或和的算术和. 2.子集的异或和的异或和. 3.子集的算术和的算术和 ...
- Java报错信息 java.lang.SecurityException: Prohibited package name: java.xxx
package java.yun.System; public class SystemOut { public static void main(String[] args) { System.ou ...
- C++ bitset用法
概念: bitset是用来存储位的(其中的元素只有两种形式) 这个类通常用来模拟一个布尔数组,但对空间分配上进行了优化:通常,每个元素只占用一个bit ,而通常char类型是它的八倍 每个位置上的位都 ...
- Docker的简单实用
一.docker的常用操作 二.其实用docker search images它就是去hub仓库里面查找:https://hub.docker.com/ 对容器的操作: 搜索镜像:[root@mast ...
- 从YOLOv1到v3的进化之路
引言:如今基于深度学习的目标检测已经逐渐成为自动驾驶,视频监控,机械加工,智能机器人等领域的核心技术,而现存的大多数精度高的目标检测算法,速度较慢,无法适应工业界对于目标检测实时性的需求,这时YOLO ...
- Python基础练习题100例(Python 3.x)
1:题目:有四个数字:1.2.3.4,能组成多少个互不相同且无重复数字的三位数?各是多少? 程序分析:可填在百位.十位.个位的数字都是1.2.3.4.组成所有的排列后再去 掉不满足条件的排列. 程序源 ...
- Android 8.1 源码_启动篇(一) -- 深入研究 init(转 Android 9.0 分析)
前言 init进程,它是一个由内核启动的用户级进程,当Linux内核启动之后,运行的第一个进程是init,这个进程是一个守护进程,确切的说,它是Linux系统中用户控件的第一个进程,所以它的进程号是1 ...