19

Code First Migrations で Entity Framework 5 を使用しています。私DataStoreはから派生したクラスを持っていますDbContext:

public class DataStore : DbContext, IDataStore
{
    public int UserID { get; private set; }

    public DataStore(int userId, string connectionString) : base(connectionString)
    {
        UserID = userId;
    }

    public virtual IDbSet<User> Users { get; set; }

    // Rest of code here
}

そして、クラスのインスタンスを作成するファクトリDataStoreクラス:

public class DataStoreFactory : Disposable, IDataStoreFactory
{
    private DataStore _database;
    private int _userId;
    private string _connectionString;

    public DataStoreFactory(int userId, string connectionString)
    {
        _userId = userId;
        _connectionString = connectionString;
    }

    public IDataStore Get()
    {
        _database = new DataStore(_userId, _connectionString);
        return _database;
    }

    protected override void DisposeCore()
    {
        if (_database != null) _database.Dispose();
    }
}

これらのクラスには、実行時にUnityで注入されたコンストラクター パラメーターがあります。これまでのところ、すべてがうまく機能しています。

問題は、移行に到達したときに発生します。私のDataStoreコンテキスト クラスには既定のコンストラクターがないIDbContextFactory<T>ため、Code First Migrations がそれをインスタンス化できるように、の実装を提供する必要があります。

public class MigrationDataStoreFactory : IDbContextFactory<DataStore>
{
    public DataStore Create()
    {
        // Need to inject connection string so we can pass it to this constructor
        return new DataStore(0, "CONNECTION_STRING_NEEDED_HERE"); 
    }
}

問題は、接続文字列をこのクラスに挿入する方法がわからないことです。次のような接続文字列パラメーターを使用して新しいコンストラクターを作成できません。

public class MigrationDataStoreFactory : IDbContextFactory<DataStore>
{
    public string _connectionString { get; set; }

    public MigrationDataStoreFactory(string connectionString)
    {
        _connectionString = connectionString;
    }

    public DataStore Create()
    {
        return new DataStore(0, new DateTimeProvider(() => DateTime.Now), _connectionString);
    }
}

その場合、実行時に移行によって次の例外がスローされます。

[InvalidOperationException: The context factory type 'MigrationDataStoreFactory' must have a public default constructor.]
    System.Data.Entity.Infrastructure.DbContextInfo.CreateActivator() +326
    System.Data.Entity.Infrastructure.DbContextInfo..ctor(Type contextType, DbProviderInfo modelProviderInfo, AppConfig config,     DbConnectionInfo connectionInfo) +106
    System.Data.Entity.Infrastructure.DbContextInfo..ctor(Type contextType) +52
    System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration, DbContext usersContext) +202
    System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration) +66
    System.Data.Entity.MigrateDatabaseToLatestVersion`2.InitializeDatabase(TContext context) +50
    // Truncated stack trace, but you get the idea

それを除けば、このクラスはとにかく Unity によってインスタンス化されません。どういうわけかCode First Migrationsによって慣例によって呼び出されているように見えるので、それができたとしても、それは本当に役に立ちません...

そのメソッドで接続文字列をハードコーディングすると、すべてが正常に機能しますが、明らかな理由から、それを行いたくありません。

誰でも助けてもらえますか?

4

3 に答える 3

22

Entity Framework 6 へのアップグレードが実行可能な場合は、移行の初期化の新しいオーバーロードがあり、これがはるかに簡単になります。

    // Parameters:
    //   useSuppliedContext:
    //     If set to true the initializer is run using the connection information from the
    //     context that triggered initialization. Otherwise, the connection information
    //     will be taken from a context constructed using the default constructor or registered
    //     factory if applicable.
    public MigrateDatabaseToLatestVersion(bool useSuppliedContext);

これを使用すると、次のように挿入された DbContext で移行を実行できます。

Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDbContext, MyMigrationConfiguration>(useSuppliedContext: true));

using (var context = kernel.Get<MyDbContext>())
    context.Database.Initialize(false);
于 2015-09-09T11:38:54.680 に答える