より良いエンジニアを目指して

1日1つ。良くなる!上手くなる!

ASP.NET Entityframework Coreのチュートリアル「Contoso大学」に入学してみる

ASP.NET EntityframeworkCoreのチュートリアルMSDNにはあります。

docs.microsoft.com

このチュートリアルを参考にContoso UniversityというWebアプリケーションページを作ってみました。

f:id:rimever:20190919184935p:plain

var student = await _context.Students
        .Include(s => s.Enrollments)
            .ThenInclude(e => e.Course)
        .AsNoTracking()
        .FirstOrDefaultAsync(m => m.ID == id);

そんな構文あるのか、と。

過剰ポスティングへの対策も紹介されています。

EntityframeworkだけでなくASP.NET MVCとしてのテクニックも学べるので下手な本やWeb記事(このブログとかね)を読むよりは、まずこのチュートリアルを触ることをお勧めします。

公式ドキュメント重要。

かなりやりごたえのある内容で3日くらいかかりました。

EntityframeworkCoreの使い所

Entityframeworkに限らず、O/Rマッパーは全てのテーブル設計をカバー仕切れるとは言い難いです。

実際にアプリケーションを作るならばDapperを使った方が無難でしょう。

デモアプリ等を作成する際にはスキャフォールディングも合わせて使うと手間が省けるので、ASP.NET MVC + EntityframeworkCore + Sqliteのスタックを用意してます。

トラブルシューティング

コンカレンシーの競合は、上手く機能しませんでした。なぜだろう・・・。

EntityframeworkCore.SqliteでDbInitializerが機能しない

Microsoft.EntityframeoworkCore.Sqliteのバージョンが噛み合わないとうまく行かないときがあるようです。

The type initializer for 'SQLite.SQLiteConnection' threw an exception

よくわからないのですが、ダウングレードすると問題が解消されました。私が正常動作したcsprojの内容は以下です。

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.2</TargetFramework>
    <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
  </PropertyGroup>


  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.App" />
    <PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.0" />
  </ItemGroup>

</Project>

String.FormatException

System.FormatException: Input string was not in a correct format. at System.Text.StringBuilder.FormatError() at System.Text.StringBuilder.AppendFormatHelper(IFormatProvider provider, String format, ParamsArray args) at System.String.FormatHelper(IFormatProvider provider, String format, ParamsArray args) at System.String.Format(IFormatProvider provider, String format, Object arg0) at Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.TemplateBuilder.Build() at Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelper.GenerateDisplay(ModelExplorer modelExplorer, String htmlFieldName, String templateName, Object additionalViewData) at Microsoft.AspNetCore.Mvc.Rendering.HtmlHelperDisplayExtensions.DisplayForTModel,TResult

こんなコードを書いてました。

        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd", ApplyFormatInEditMode = true)]

{0:yyyy-MM-dd}}が抜けていました。DisplayFormatの宣言ミスです。

        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]

System.InvalidOperationException: No service for type 'SchoolContext' has been registered.

System.InvalidOperationException: No service for type 'SchoolContext' has been registered.
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredServiceT
at Program.Main(String[] args) in Program.cs

Startup.csに以下の一行が追加されているか確認してください。

services.AddDbContext();

        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
            services.AddDbContext<SchoolContext>();
        }