.NET CoreでDBアクセスといえば、各種紹介記事やドキュメント、チュートリアルでも Entity Framework Core がよく紹介されています。 個人的にはずいぶん小回りも効くようになってすごくよくなってると思いますし、.NET CoreでのDBアクセス周りは、まずはEntity Framework Coreを使うところから始めてよいように思っています。
とはいえ、そこはやはりコンテキスト次第ではあると思うので、後学のために調べてみました。
System.Data.SqlClientを使ってみる
では実際に試してみます。 適当にASP.NET CoreのWebアプリケーションを作成しておきます(認証は無しを選んでおきます)。環境はVS2015 Community 以上を想定します。 対処のDBはとりあえず SQL Serverとします。
CoreFxにおける非EFについのてドキュメントがぱっとみで見当たらなかったのですが、『きっとSystem.Data.SqlClientがそのまま存在するに違いない』と思って検索してみると……やはりありました。
ということでまずはインストールしておきます。
PM> Install-Package System.Data.SqlClient GET https://api.nuget.org/v3/registration1-gz/system.data.sqlclient/index.json GET https://www.nuget.org/api/v2/curated-feeds/microsoftdotnet/Packages(Id='System.Data.SqlClient',Version='4.1.0') OK https://www.nuget.org/api/v2/curated-feeds/microsoftdotnet/Packages(Id='System.Data.SqlClient',Version='4.1.0') 282ms OK https://api.nuget.org/v3/registration1-gz/system.data.sqlclient/index.json 376ms 'nuget.org' からパッケージ 'System.Data.SqlClient 4.1.0' を取得しています。 NuGet パッケージ System.Data.SqlClient.4.1.0 をインストールしています。 'System.Data.SqlClient 4.1.0' が CoreFxDbSample に正常にインストールされました NuGet の操作の実行に 37.83 ms かかりました 経過した時間: 00:00:02.3787366
スクリーンショットにはないですが、ドリルダウンすると、System.Data.Common何かもちゃんと在って、見ていることが分かります。
プロバイダがインストールされたので、適当なSQL Serverに接続してみます。読むテーブルは取り合ずこんな感じのシンプルな奴だと思ってください。
CREATE TABLE [dbo].[User] ( [Id] INT NOT NULL, [Name] NVARCHAR (50) NOT NULL, [Email] NVARCHAR (255) NOT NULL, [BirthDay] DATETIME NOT NULL, PRIMARY KEY CLUSTERED ([Id] ASC) );
データには何か適当にレコードを入れておきました。
とりあえずサンプルなのでHomeControllerに直接書いてみます。何の変哲もない、ADO.NETで普通に接続型でDBを読む場合とまったく同じコードだと思います。 接続文字列はVisual Studioのサーバーエクスプローラーで選択してプロパティからコピーしたものをそのまま使っています*1。
// HomeController.cs using Microsoft.AspNetCore.Mvc; using System.Collections.Generic; using System.Data.SqlClient; namespace CoreFxDbSample.Controllers { public class HomeController : Controller { public IActionResult Index() { ViewBag.Users = new List<string>(); using (var con = new SqlConnection("<接続文字列>")) using (var cmd = new SqlCommand("SELECT Name FROM Users WHERE Id <= @Id", con)) { cmd.Parameters.Add(new SqlParameter() { ParameterName = "Id", Value = 2, DbType = System.Data.DbType.Int32 }); con.Open(); using (var dr = cmd.ExecuteReader()) { while (dr.Read()) { ViewBag.Users.Add(dr["Name"].ToString()); } } } return View(); } } }
ついでに結果を見るためにHome/Index.cshtmlもばっさり書き換えておきます。
<!-- Home/Index.cshtml --> @{ ViewData["Title"] = "Home Page"; } <h1>DataReader Sample</h1> <ul> @foreach (var item in ViewBag.Users) { <li>@item</li> } </ul>
実行してみると、普通に表示されます。
この例のとおり、DbConennction, DbCommand , DbParameter, DbDataReaderなど、ADO.NETの基本的な仕組みはポーティングされていて、SQL Server用のプロバイダでもちゃんと実装されていることが分かりました。
NetFxのADO.NETを接続型で使う場合と比較して特に違和感が無い…というか全く同じように使えることが期待できますね。
NetFxのADO.NETと比較した制限(2016/10/15 現在)
とはいえ、そのまま移植されているわけではなく、現時点(.NET Core 1.0.1)では利用できない機能がいくつかあります。
DataSetやDataTableはまだ実装されていない(もうすぐ入りそう)
DataSetやDataTable、DataAdapterなど、ADO.NETの非接続型の機能を提供するクラスは、現時点(.NET Core 1.0.1)では実装されていません(何か依存物のコンパイルを通すためか、DataTableのみ空で実装はされている模様)。
これらはNetFxでももはやレガシーな機能ですし、WinFormやWebFormなどDataSetを前提としたコンポーネントを活用する(これまたレガシーな)機能は.NET Coreで実装される予定が(今のところ)なさそうなので、このまま実装されずに終わるかな……と思っていたのですが、なんと、ごく最近になってcorefxのmasterにマージされました*2!
ということで、近い将来のリリースあたりで入ってくるんじゃないかと思います。
DataTableに依存した機能は使えない(2016/10/15 現在)
DataTable自体を欲していなくても、DataTableが無いと利用できない機能というのがいくつかあります。私が思いついたのは以下です。 (ただし前述のとおりDataTableが実装されてくれば、将来的にはこれらもちゃんと機能するようになることが期待できそうです。)
Table Value Parameter (テーブル値パラメータ/TVP)
SQL Serverの便利な機能であるTable Value Parameterを.NETのコードから利用する場合、DataTableに格納して渡すことになります。しかし、.NET Core 1.0.1ではDataTableが実装されていないので利用することができません。
SqlConnection.GetSchema
接続先のスキーマ情報を取得するメソッドですが、この戻り値がDataTableだるため、現在は利用できません(GetSchemaが実装されていない)。
まとめ
.NET Core 1.0.1の現時点でもDbConnection, DbCommand, DbDataReaderなどの基本的なものは実装されていて、NetFxのADO.NETで利用するのと違和感なく利用できるようです。 現時点のリリースではDataSetやDataTableがまだ実装されていませんが、近い将来のリリースでは含まれてきそうです。
*1:SQL Server認証の場合はパスワードが*になるので書き換える必要があります
*2:これらレガシーな機能がまるっと実装された(だだしTableAdapter はなさそう)理由はよくわかりません。ただ後述のとおりDataTableに依存した機能がいくつかあって、そのためDataTableの実装を望む声は上がっていたようですので、そのあたりも関係しているかもしれません。DataSetについてはどうなんよと思うのですが、ちょっとDataTableのソースを眺めてみた感じではそのなかでもDataSetに依存したコードもあるように見えたので、そう簡単に切り離せるものでは無いのかもしれません。