対象読者
- 新しいASP.NET Coreの機能について知りたい方
- MacやLinuxなどでASP.NET Coreアプリケーションを動かしたい方
- Entity Framework Coreの新機能について知りたい方
検証環境
本稿では、以下の環境で動作を確認しています。
- macOS High Sierra 10.13.3
- .NET Core 2.0
コントローラーの作成
前回作成したコンテキストクラスを使って、データベースアクセスをするコードを書いていきます。
Blogコントローラー
Blogコントローラーにはこのサイトで閲覧できるブログの一覧を返すメソッドと、作者名を検索条件にした絞り込み検索を行うメソッドを用意します。
・・・中略
[Route("api/[controller]")]
public class BlogController : Controller
{
    private readonly Efcore2Context _context;
    // アプリケーションが保持するコンテキストインスタンスを注入する
    public BlogController(Efcore2Context context) ・・・(1)
    {
        _context = context;
    }
    [HttpGet("[action]")]
    public IEnumerable<Blog> Blogs()
    {
        // blogテーブルからデータを全件取得する
        return _context.Blogs.ToList(); ・・・(2)
    }
    [HttpGet("[action]")]
    public IEnumerable<Blog> FindByAuthor(string author)
    {
        // 作者名で絞り込み検索をする
        return _context.Blogs
            .FromSql($"select * from blog where author = {author}") ・・・(3)
            .ToList();
    }
}
  Blogコントローラーのコンストラクタでコンテキストのインスタンスを受け取り、コントローラーのプライベートフィールドにセットしています(1)。コンテキストインスタンスは前回のStartup.csで生成したものをコンストラクタ経由で受け取るため、コントローラー側では生成を行いません。Blogsメソッドではblogテーブルのデータを全件取得します(2)。ここでは、コンテキストインスタンスのパブリックフィールドであるBlogsを参照しています。
BlogsはDbSet<Blog>型であり、DbSetは指定したエンティティのコレクションを表します。この場合はBlog型を指定しているため、対応するblogテーブルのデータにアクセスすることができます。ここではToListメソッドにより、blogテーブルからデータを全件取得し、エンティティにマッピングしたものをリスト(IEnumerable型)にして返却しています。
一方FindByAuthorメソッドでは、メソッドの引数(作者名)を検索条件とした絞り込み検索を行います(3)。ここではデータアクセスにFromSqlメソッドを使用しています。これは文字列で記述したSQL文を直接実行することのできるメソッドです。
Entity Framework Core 2.0からは、このFromSqlメソッドで文字列補間(string interpolation)が使用できるようになりました。ここでは「{author}」と記述した箇所が文字列補間によって置き換えられます。文字列補間が使用できるようになったことで、パラメータ化クエリとしてSQLが評価・実行されます。これにより、SQLインジェクションの回避やパフォーマンスの向上が期待できます。
Post(記事)コントローラー
Postコントローラーにはブログに含まれる記事の一覧を返すメソッドと、記事のタイトルであいまい検索を行うメソッドを用意します。
・・・中略
[Route("api/[controller]")]
public class PostController : Controller
{
    private readonly Efcore2Context _context;
    // アプリケーションが保持するコンテキストインスタンスを注入する
    public PostController(Efcore2Context context)
    {
        _context = context;
    }
    [HttpGet("[action]")]
    public IEnumerable<Post> Posts(string blogId)
    {
        // あるブログの記事一覧を取得する(blogIdで絞り込み) ・・・(1)
        return _context.Posts
            .Where(post => post.blog_id == blogId)
            .ToList();
    }
    [HttpGet("[action]")]
    public IEnumerable<Post> FindByTitle(string title)
    {
        // 「検索文字列 + %」で記事タイトルの前方一致検索をする ・・・(2)
        return _context.Posts
            .Where(post => EF.Functions.Like(post.post_title, title + "%"))
            .ToList();
    }
}
  Postsメソッドは、ある特定のブログの記事一覧を返すように実装しています(1)。クライアント側から受け取ったブログのID(blogID)で絞り込み検索をするために、Whereメソッドを使ってフィルタリングを行っています。
WhereメソッドはDbSetからエンティティオブジェクトを1件ずつ取り出して、指定した条件に合致するかどうかを評価します。この場合は「post.blog_id == blogId」の部分が条件になります。メソッドは条件に合致したエンティティのみで構成されるコレクションを戻り値として返却します。
Whereメソッドのように、エンティティのコレクションをフィルタリングする他にも、変換、集計やソートをするメソッドがC#には用意されています。これらを総称してLINQ(統合言語クエリ)と呼び、特にEntity Frameworkの操作に特化したものをLINQ to Entitiesと呼びます。
次に、FindByTitleメソッドは記事のタイトルから特定の記事を検索するメソッドです(2)。ここでは、入力された文字列から前方一致でタイトルを検索できるメソッドにします。
SQLでは一般的にLIKE句を使って前方一致検索を行いますが、Entity Framework Core 2.0で新たに導入されたLikeオペレータを使って、同様のことが行えるようになりました。これには、LINQのWhereメソッドで「EF.Functions.Like()」というオペレータを使用します。第一引数にはLike句の対象となるフィールド名を、第二引数には検索文字列を設定します。今回は前方一致検索をするため、「検索文字列」と「%」の結合文字列を設定しています。

 
              
               
                          
                           
                          
                           
                          
                           
                          
                           
                          
                           
                          
                           
                          
                           
                          
                           
                          
                           
                          
                           
                          
                           
                              
                               
                              
                               
                              
                               
                              
                               
                              
                               
                      
                     
                      
                     
                      
                     
                      
                     
                      
                     
                      
                     
                      
                     
															
														 
															
														.png) 
     
     
     
     
     
													 
													 
													 
													 
													 
										
									
 
                     
                    