LoginSignup
0
0

C#でGraphQL(ホットチョコレートとEFCore)その3

Last updated at Posted at 2023-10-30

引き続き、ホットチョコレートを調査しました。
今回はSQLServerに接続します。
N+1とかどうなるんでしょうか
※ちなみにホットチョコレートは、Microsoft.NETベースのGraphQLサーバです。

前回の記事はこちら
C#でGraphQLその2

前回に続き、簡単でした!

結論としては
SQLServerへの接続はEFCoreの導入とホットチョコレートのプロジェクションと呼ばれる機能を使うようです。
主な変更点は以下のQueryクラスの変更とEFCoreの設定になります。

  • 新規にUseProjectionアトリビュートを追加する。
  • データソースをEFCoreのDbContextにする。
  • あとここキモですが返値の型は"IQueryable"にしろと(このあとSQLを構築するんでしょうね)
    public class Query
    {
        [UseProjection]
        [UseFiltering]
        public IQueryable<Author> Authors([Service] AppDbContext dbContext)
        {
            return dbContext.Authors;
        }
        [UseProjection]
        [UseFiltering]
        public IQueryable<Book> Books([Service] AppDbContext dbContext)
        {
            return dbContext.Books;
        }
    } 
    

テスト

image.png

以下が発行されたSQLですが、Joinしてくれてますねー

Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (1ms) [Parameters=[@__p_0='?' (Size = 256)], CommandType='Text', 
CommandTimeout='30']
SELECT [a].[Name], [a].[Id], [b].[Title], [b].[Id]
FROM [Authors] AS [a]
LEFT JOIN [Books] AS [b] ON [a].[Id] = [b].[AuthorId]
WHERE ([a].[Name] IS NOT NULL) AND ((@__p_0 LIKE N'') OR CHARINDEX(@__p_0, [a].[Name]) > 0)
ORDER BY [a].[Id]

疑問

ここで疑問がわきます。
AuthorテーブルとBookテーブルの関連性はどう解釈しているのでしょうか。
これについては、EFCoreの機能になるようです。
次のAppDbContextをマイグレーションすると

public class AppDbContext : DbContext
{
    public AppDbContext() { }
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
    public DbSet<Author> Authors { get; set; }
    public DbSet<Book> Books { get; set; }

    public class Author
    {
        public int Id { get; internal set; }
        public string Name { get; set; }
        public List<Book> Books { get; set; }
    }
    public class Book
    {
        public int Id { get; internal set; }
        public string Title { get; set; }
        public Author Author { get; set; }
    }
}

次のSQLServerテーブルが生成されます。
Booksテーブルに自動的にAuthorIdとFKが追加されているのがわかります。
このId(あとFK)でリレーションを判断しているようです。(おそらく)
image.png

感想

いやあ素晴らしいですねGraphQL(ホットチョコレート)!
あとEFCoreとの相性も。
結局ここまで50行程度のプログラムで実現できました。
適切に設計されたエンティティがあれば、ほぼノーコードで
プログラムいらんやん!
仕事がなくなる...

手順まとめ

  1. EFCore関連モジュール導入

    dotnet add package HotChocolate.Data.EntityFramework
    dotnet add package Microsoft.EntityFrameworkCore
    dotnet add package Microsoft.EntityFrameworkCore.Desinge
    dotnet add package Microsoft.EntityFrameworkCore.SqlServer
    
  2. Progoram.csを以下で上書きしてください(いいかげんコード分割しなければ…)

    using Microsoft.EntityFrameworkCore;
    using static AppDbContext;
    
    //ASP.NET Core定義
    var builder = WebApplication.CreateBuilder(args);
    builder.Services
        .AddDbContext<AppDbContext>(options => options.UseSqlServer("Data Source=(localdb)\\MSSQLLocaldb;Initial Catalog=GraphQL;Integrated Security=True"))
        .AddGraphQLServer()
        .RegisterDbContext<AppDbContext>()
        .AddQueryType<Query>()
        .AddProjections()
        .AddFiltering();
    var app = builder.Build();
    
    app.MapGraphQL();
    
    app.Run();
    
    //GraphQL(HotChocolate)のQuery定義
    public class Query
    {
        [UseProjection]
        [UseFiltering]
        public IQueryable<Author> Authors([Service] AppDbContext dbContext)
        {
            return dbContext.Authors;
        }
        [UseProjection]
        [UseFiltering]
        public IQueryable<Book> Books([Service] AppDbContext dbContext)
        {
            return dbContext.Books;
        }
    }
    
    //EFCore定義(Context,Entity)
    public class AppDbContext : DbContext
    {
        public AppDbContext() { }
        public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
        public DbSet<Author> Authors { get; set; }
        public DbSet<Book> Books { get; set; }
    
        public class Author
        {
            public int Id { get; internal set; }
            public string Name { get; set; }
            public List<Book> Books { get; set; }
        }
        public class Book
        {
            public int Id { get; internal set; }
            public string Title { get; set; }
            public Author Author { get; set; }
        }
    }
    
  3. あとマイグレーションとかデータ登録とか
    ※あらかじめSQLServerのDB作っておいてください

      dotnet ef migrations add CreateDB
      dotnet ef database update
    
    INSERT INTO Authors VALUES(N'川端康成');
    INSERT INTO Authors VALUES(N'夏目漱石');
    INSERT INTO Books VALUES(N'雪国', 1);
    INSERT INTO Books VALUES(N'伊豆の踊子', 1);
    INSERT INTO Books VALUES(N'坊ちゃん', 2);
    INSERT INTO Books VALUES(N'三四郎', 2);
    
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0