Entity Framework と ASP.NET Identity2 で Oracle の DB に接続する

ASP.NET MVC5 & Entity Framework & Identity2 のプロジェクトを作り、Oracle に接続するようにする。
結果として、サンプルアプリケーションでユーザーの登録やログインができる状態にする。

上記の構成で少しつまづいた所があったので、記事としてまとめました。

# プロジェクトの作成

ASP.NET MVC のプロジェクトを作成する。

認証は個人ベース。（デフォルトでもある）
テストに関するオプションはデフォルト。

# NuGet

Oracle Managed Data Access を取得する。

* Oracle.ManagedDataAccess
* Oracle.ManagedDataAccess.EntityFramework

## GAC への登録

### 何故？

これがないと、後で行う Update-Database が失敗してしまう。

```:GACに登録しなかった場合のエラー例
PM> Update-Database
 :
System.Runtime.Serialization.SerializationException: メンバー 'Oracle.ManagedDataAccess.Client.OracleException,Oracle.ManagedDataAccess, Version=4.121.2.0, Culture=neutral, PublicKeyToken=89b483f429c47342' の型が解決されていません。
```

### gacutil で登録する

[この stack overflow](http://stackoverflow.com/questions/32006884/entity-framework-seed-method-exception) を見て解決。

管理者権限でコマンドプロンプトを起動して、以下のコマンドを実行する。

```:実行
pushd {プロジェクトフォルダ}\packages\Oracle.ManagedDataAccess.12.1.2400\lib\net40
"c:\Program Files\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\gacutil.exe" /i Oracle.ManagedDataAccess.dll
```

パスは適宜読み替えて下さい。

# Oracle への接続設定
## まずは、ユーザーを用意

てきとーにテストユーザー __EFTEST__ を作成。

```sql
CREATE USER EFTEST IDENTIFIED BY pasuwado
    DEFAULT TABLESPACE EFTEST_TABLESPACE 
    TEMPORARY TABLESPACE TEMP 
    ACCOUNT UNLOCK;
GRANT ALL privileges TO EFTEST;
GRANT DBA TO EFTEST;
```

## Web.config の connectionStrings を編集

```xml:Web.configの編集箇所のみ
  <connectionStrings>
    <!-- 
      <add name="DefaultConnection"
            connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\aspnet-WebApplication2-20160902013704.mdf;Initial Catalog=aspnet-WebApplication2-20160902013704;Integrated Security=True" 
            providerName="System.Data.SqlClient" />
      <add name="OracleDbContext"
            providerName="Oracle.ManagedDataAccess.Client"
            connectionString="User Id=oracle_user;Password=oracle_user_password;Data Source=oracle" />
    -->
    <add name="DefaultConnection"
            providerName="Oracle.ManagedDataAccess.Client"
            connectionString="User Id=EFTEST;Password=pasuwado;Data Source=dbserver/orcl" />
  </connectionStrings>
```

DefaultConnection で、先程用意したDBに接続するように記述する。

Entity Framework のコンテキストを弄ると若干面倒なので、この記事では、IdentityDbContext が参照しているこの DefaultConnection を使って接続するように変更していく。

コメントアウトされている DefaultConnection は、プロジェクト作成時に用意されているもので、SQL Server Express LocalDB に接続するようになっている。
今回は Oracle に接続するので、この connectionString は、そのままでは使えない。

また、同様にコメントアウトされている OracleDbContext は、先程の NuGet の時点で追加されている。
接続先や使うプロバイダの情報としてはこちらが最終形に近い。

結果として、最終行の設定となる。

# 接続先ユーザーの指定をする

そのままだと、dbo というユーザーに接続しようとする。

ここでは IdentityDbContext に対して、コードで明示的にユーザーを指定する。

こちらの記事→[空のプロジェクトからASP.NET MVC5 EntityFramework6 for Oracleを試す](http://qiita.com/yaju/items/3b1b5fb77ff684d564f9#%E4%BE%8B%E5%A4%96%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%8C%E7%99%BA%E7%94%9F) にあるように修正する。

```vbnet
Public Class ApplicationDbContext
    Inherits IdentityDbContext(Of ApplicationUser)
    Public Sub New()
        MyBase.New("DefaultConnection", throwIfV1Schema:=False)
    End Sub

    'このサブプロシージャーを追加する。
    Protected Overrides Sub OnModelCreating(modelBuilder As DbModelBuilder)
        MyBase.OnModelCreating(modelBuilder)

        ' ここで Oracle ユーザーを指定している。
        modelBuilder.HasDefaultSchema("EFTEST")
    End Sub

    Public Shared Function Create() As ApplicationDbContext
        Return New ApplicationDbContext()
    End Function
End Class
```

# マイグレーションの設定をする

今回は AutomaticMigration は有効にしない。

パッケージ マネージャー コンソールから、以下のコマンドを実行する。

```:
PM> Enable-Migrations

Checking if the context targets an existing database...
Code First Migrations enabled for project WebApplication2.

PM> Add-Migration Initial

Scaffolding migration 'Initial'.
The Designer Code for this migration file includes a snapshot of your current Code First model. This snapshot is used to calculate the changes to your model when you scaffold the next migration. If you make additional changes to your model that you want to include in this migration, then you can re-scaffold it by running 'Add-Migration Initial' again.

PM> Update-Database -Verbose
```

# 実行してユーザーの追加とログインができることを確認する

プロジェクト作成時に用意されるサンプルアプリケーションを実行し、Register したり Log off / Log in したりしてみる。

テーブル EFTEST.AspNetUsers にレコードが作成されていることを確認する。

```sql
select * from "AspNetUsers";
```

# マイグレーションを最初からやり直したい場合

__MigrationHistory というテーブルと、AspNetで始まる名前のオブジェクト（テーブルや順序）を DROP する。

```sql:削除対象を洗い出すSQL文
select * from user_objects where object_name like '%Asp%' order by object_name;
```

```sql:結果的に実行したDROP文
drop table "__MigrationHistory";
-- ↓外部キーの参照があるため順番を入れ替えて実行します。
drop table "AspNetUserClaims";
drop table "AspNetUserRoles";
drop table "AspNetUserLogins";
drop table "AspNetUsers";
drop table "AspNetRoles";
drop sequence "SQ_AspNetUserClaims";
```