4

Web サイトで Entity Framework コード ベースの移行を使用しようとしています。現在、複数のプロジェクトを含むソリューションがあります。データベースを初期化したいWeb APIプロジェクトと、DataLayerプロジェクトと呼ばれる別のプロジェクトがあります。DataLayer プロジェクトで移行を有効にし、データベースが存在しない場合にデータベースを作成するために使用されることを期待している初期移行を作成しました。

移行を有効にしたときに得た構成は次のとおりです

public sealed class Configuration : DbMigrationsConfiguration<Harris.ResidentPortal.DataLayer.ResidentPortalContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
    }

    protected override void Seed(Harris.ResidentPortal.DataLayer.ResidentPortalContext context)
    {
        //  This method will be called after migrating to the latest version.

        //  You can use the DbSet<T>.AddOrUpdate() helper extension method 
        //  to avoid creating duplicate seed data. E.g.
        //
        //    context.People.AddOrUpdate(
        //      p => p.FullName,
        //      new Person { FullName = "Andrew Peters" },
        //      new Person { FullName = "Brice Lambson" },
        //      new Person { FullName = "Rowan Miller" }
        //    );
        //
    }
}

作成後にこれに加えた唯一の変更は、内部からパブリックに変更して、WebAPI がそれを認識し、データベース初期化子で使用できるようにすることでした。以下は、データベースを初期化するために使用している Application_Start のコードのコードです。

Database.SetInitializer(new MigrateDatabaseToLatestVersion<ResidentPortalContext, Configuration>());
new ResidentPortalUnitOfWork().Context.Users.ToList();

データベースが存在するかどうかに関係なくこれを実行すると、次のエラーが発生します

ファイル「C:\Users\Dave\Documents\Visual Studio 2012\Projects\ResidentPortal\Harris.ResidentPortal.WebApi\App_Data\Harris.ResidentPortal.DataLayer.ResidentPortalContext.mdf」のディレクトリ ルックアップがオペレーティング システム エラー 2 (Theシステムは指定されたファイルを見つけることができません。)

データベースの作成に失敗しました。リストされたいくつかのファイル名を作成できませんでした。関連するエラーを確認してください。

データベースのまったく間違った場所を探しているようです。コードを次のように変更すると、データベースを初期化するこの特定の方法と関係があるようです。

Database.SetInitializer(new DropCreateDatabaseAlways<ResidentPortalContext>());
new ResidentPortalUnitOfWork().Context.Users.ToList();

データベースは、必要な場所に正しく作成されます。

何が原因なのか途方に暮れています。構成クラスに何か他のものを追加する必要があるのでしょうか、それともすべての移行情報が DataLayer プロジェクトにあるのに WebAPI プロジェクトからこれを呼び出しているという事実と関係があるのでしょうか?

4

1 に答える 1

8

このプロセスの動的接続文字列を作成する方法を理解しました。Web または App.Config の EntityFramework エントリに、既定で配置される行ではなく、最初にこの行を追加する必要があります。

<defaultConnectionFactory type="<Namespace>.<ConnectionStringFacotry>, <Assembly>"/>  

これは、DbConnection を返す独自のファクトリがあることをプログラムに伝えます。以下は、自分の工場を作るために使用したコードです。これの一部は、多数のプログラマーが同じコード セットで作業しているという事実を利用するためのハックですが、一部のプログラマーは SQL Express を使用し、他のプログラマーは本格的な SQL Server を使用しています。しかし、これはあなたが必要とするもののために行くための例をあなたに与えるでしょう.

public sealed class ResidentPortalConnectionStringFactory: IDbConnectionFactory 
{
    public DbConnection CreateConnection(string nameOrConnectionString)
    {
        SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(ConfigurationManager.ConnectionStrings["PortalDatabase"].ConnectionString);

        //save off the original catalog
        string originalCatalog = builder.InitialCatalog;

        //we're going to connect to the master db in case the database doesn't exist yet
        builder.InitialCatalog = "master";
        string masterConnectionString = builder.ToString();

        //attempt to connect to the master db on the source specified in the config file
        using (SqlConnection conn = new SqlConnection(masterConnectionString))
        {
            try
            {
                conn.Open();
            }
            catch
            {
                //if we can't connect, then append on \SQLEXPRESS to the data source
                builder.DataSource = builder.DataSource + "\\SQLEXPRESS";
            }
            finally
            {
                conn.Close();
            }
        }

        //set the connection string back to the original database instead of the master db
        builder.InitialCatalog = originalCatalog;

        DbConnection temp = SqlClientFactory.Instance.CreateConnection();
        temp.ConnectionString = builder.ToString();

        return temp;
    }
}

それをしたら、Global.asaxでこのコードを問題なく実行できます

Database.SetInitializer(new MigrateDatabaseToLatestVersion<ResidentPortalContext, Configuration>());
using (ResidentPortalUnitOfWork temp = new ResidentPortalUnitOfWork())
{
    temp.Context.Database.Initialize(true);
}
于 2013-04-16T20:19:51.790 に答える