2018年9月28日金曜日

EntityFrameworkでSQLiteを使ってみた!

Entity FrameworkもSQLiteもそれぞれ使ったことはあるのですが、今回初めてEntity FrameworkからSQLiteを使ったので
その方法をメモ。

まず、System.Data.SQLite.EF6.Migrationsパッケージをインストールします。
この時、もれなく

・EntityFramework
・System.Data.SQLite.Core
・System.Data.SQLite.EF6
・System.Data.SQLite.Linq
・System.Data.SQLite

もインストールされます。

DbContextクラス、エンティティクラスを作成します。

public class SampleDbContext : DbContext
{
    public DbSet<user> Users { get; set; }

    public SampleDbContext() : base("name = Sample")
    {
    }
}

public class User
{
    public int Id { get; set; }

    public string Name { get; set; }
}


App.configに接続文字列を追加します。


<connectionStrings>
  <add name="Sample" connectionString="Data Source=C:\xxxxx\sample.db;" providerName="System.Data.SQLite.EF6" />
</connectionStrings>

enable-migrations/add-migrationを実行すると、エラーが発生しました。

> enable-migrations
No Entity Framework provider found for the ADO.NET provider with invariant name 'System.Data.SQLite'. Make sure the provider is registered in the 'entityFramework' section of the application config file. 

> add-migration InitialCreate
No Entity Framework provider found for the ADO.NET provider with invariant name 'System.Data.SQLite'. Make sure the provider is registered in the 'entityFramework' section of the application config file. 


エラー内容に従って、App.configに設定を追加します。


<providers>
  <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
  <provider invariantName="System.Data.SQLite.EF6" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" />
  <provider invariantName="System.Data.SQLite" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" />
</providers>

再び、add-migrationを実行します。

> add-migration InitialCreate
System.ObjectDisposedException: 破棄されたオブジェクトにアクセスできません。
オブジェクト名 'SQLiteConnection' です。
   場所 System.Data.SQLite.SQLiteConnection.CheckDisposed()
   場所 System.Data.SQLite.SQLiteConnection.get_State()
   場所 System.Data.Entity.Internal.RepositoryBase.CreateConnection()
   場所 System.Data.Entity.Migrations.History.HistoryRepository.QueryExists(String contextKey)
   場所 System.Data.Entity.Migrations.History.HistoryRepository.Exists(String contextKey)
   場所 System.Data.Entity.Migrations.History.HistoryRepository.GetPendingMigrations(IEnumerable`1 localMigrations)
   場所 System.Data.Entity.Migrations.DbMigrator.GetPendingMigrations()
   場所 System.Data.Entity.Migrations.DbMigrator.Scaffold(String migrationName, String namespace, Boolean ignoreChanges)
   場所 System.Data.Entity.Migrations.Design.MigrationScaffolder.Scaffold(String migrationName, Boolean ignoreChanges)
   場所 System.Data.Entity.Migrations.Design.ToolingFacade.ScaffoldRunner.Scaffold(MigrationScaffolder scaffolder)
   場所 System.Data.Entity.Migrations.Design.ToolingFacade.ScaffoldRunner.RunCore()
   場所 System.Data.Entity.Migrations.Design.ToolingFacade.BaseRunner.Run()
破棄されたオブジェクトにアクセスできません。
オブジェクト名 'SQLiteConnection' です。


いろいろ調べてみましたが、原因がよく分かりません。
(SQLServer用接続文字列の場合、エラーは発生しません。)
あきらめて、DbContextクラスのデフォルトコンストラクタで、接続文字列を指定することにしました。

public SampleDbContext() : base(new SQLiteConnection($"Data Source = {Properties.Settings.Default.DatabaseFilePath};"),
false)
{
}


三度、add-migrationを実行します。

> add-migration InitialCreate
No MigrationSqlGenerator found for provider 'System.Data.SQLite'. Use the SetSqlGenerator method in the target migrations configuration class to register additional SQL generators.


Configurationクラスのコンストラクタにメソッド呼び出しを追加します。

public Configuration()
{
    AutomaticMigrationsEnabled = false;
    SetSqlGenerator("System.Data.SQLite", new SQLiteMigrationSqlGenerator());
}


add-migration/update-databaseを実行するとデータベースファイルが作成されました。
余談ですが、データベースファイルパスにフルパスではなくファイル名のみ指定すると、
下記のようなエラーが発生するのでご注意を。

> update-database
System.Data.Entity.Core.ProviderIncompatibleException: CreateDatabase is not supported by the provider.
   場所 System.Data.Entity.Core.Common.DbProviderServices.DbCreateDatabase(DbConnection connection, Nullable`1 commandTimeout, StoreItemCollection storeItemCollection)
   場所 System.Data.Entity.Core.Common.DbProviderServices.CreateDatabase(DbConnection connection, Nullable`1 commandTimeout, StoreItemCollection storeItemCollection)
   場所 System.Data.Entity.Core.Objects.ObjectContext.CreateDatabase()
   場所 System.Data.Entity.Migrations.Utilities.DatabaseCreator.Create(DbConnection connection)
   場所 System.Data.Entity.Migrations.DbMigrator.EnsureDatabaseExists(Action mustSucceedToKeepDatabase)
   場所 System.Data.Entity.Migrations.Infrastructure.MigratorBase.EnsureDatabaseExists(Action mustSucceedToKeepDatabase)
   場所 System.Data.Entity.Migrations.DbMigrator.Update(String targetMigration)
   場所 System.Data.Entity.Migrations.Infrastructure.MigratorBase.Update(String targetMigration)
   場所 System.Data.Entity.Migrations.Design.ToolingFacade.UpdateRunner.RunCore()
   場所 System.Data.Entity.Migrations.Design.ToolingFacade.BaseRunner.Run()
CreateDatabase is not supported by the provider.


またいつか、どこかで。

0 件のコメント:

コメントを投稿