Impossibile allegare il file di database quando si utilizzano i comandi Entity Framework Core Migration

entity-framework-core

Domanda

Sto usando i comandi di EntityFramework Core nel database di migrazione. Il comando che sto usando è come suggerito dai documenti: dnx. si applica la migrazione ef. Il problema si verifica quando si specifica AttachDbFileName nella stringa di connessione, viene visualizzato il seguente errore: Impossibile collegare il file di database come database xxxxxxx. Questa è la stringa di connessione che sto usando: Data Source = (LocalDB) \ mssqllocaldb; Integrated Security = True; Initial Catalog = EfGetStarted2; AttachDbFileName = D: \ EfGetStarted2.mdf

Si prega di aiutare come allegare il file db in un'altra posizione. Grazie

Risposta accettata

Il core EF sembra avere problemi con AttachDbFileName o non lo gestisce affatto.

  • EnsureDeleted modifica il nome del database sul master ma mantiene qualsiasi valore AttachDbFileName , il che porta a un errore poiché non è possibile collegare il database master a un altro file.
  • EnsureCreated apre una connessione utilizzando il valore AttachDbFileName fornito, che genera un errore poiché il file del database che vogliamo creare non esiste ancora.

EF6 ha qualche logica per gestire questi casi d'uso, vedi SqlProviderServices.DbCreateDatabase , quindi tutto ha funzionato abbastanza bene.

Come soluzione alternativa ho scritto un codice hacky per gestire questi scenari:

public static void EnsureDatabase(this DbContext context, bool reset = false)
{
    if (context == null)
        throw new ArgumentNullException(nameof(context));

    if (reset)
    {
        try
        {
            context.Database.EnsureDeleted();
        }
        catch (SqlException ex) when (ex.Number == 1801)
        {
            // HACK: EF doesn't interpret error 1801 as already existing database
            ExecuteStatement(context, BuildDropStatement);
        }
        catch (SqlException ex) when (ex.Number == 1832)
        {
            // nothing to do here (see below)
        }
    }

    try
    {
        context.Database.EnsureCreated();
    }
    catch (SqlException ex) when (ex.Number == 1832)
    {
        // HACK: EF doesn't interpret error 1832 as non existing database
        ExecuteStatement(context, BuildCreateStatement);

        // this takes some time (?)
        WaitDatabaseCreated(context);

        // re-ensure create for tables and stuff
        context.Database.EnsureCreated();
    }
}

private static void WaitDatabaseCreated(DbContext context)
{
    var timeout = DateTime.UtcNow + TimeSpan.FromMinutes(1);

    while (true)
    {
        try
        {
            context.Database.OpenConnection();
            context.Database.CloseConnection();
        }
        catch (SqlException)
        {
            if (DateTime.UtcNow > timeout)
                throw;
            continue;
        }
        break;
    }
}

private static void ExecuteStatement(DbContext context, Func<SqlConnectionStringBuilder, string> statement)
{
    var builder = new SqlConnectionStringBuilder(context.Database.GetDbConnection().ConnectionString);

    using (var connection = new SqlConnection($"Data Source={builder.DataSource}"))
    {
        connection.Open();

        using (var command = connection.CreateCommand())
        {
            command.CommandText = statement(builder);
            command.ExecuteNonQuery();
        }
    }
}

private static string BuildDropStatement(SqlConnectionStringBuilder builder)
{
    var database = builder.InitialCatalog;

    return $"drop database [{database}]";
}

private static string BuildCreateStatement(SqlConnectionStringBuilder builder)
{
    var database = builder.InitialCatalog;

    var datafile = builder.AttachDBFilename;
    var dataname = Path.GetFileNameWithoutExtension(datafile);

    var logfile = Path.ChangeExtension(datafile, ".ldf");
    var logname = dataname + "_log";

    return $"create database [{database}] on primary (name = '{dataname}', filename = '{datafile}') log on (name = '{logname}', filename = '{logfile}')";
}

È tutt'altro che bello, ma lo sto comunque utilizzando per i test di integrazione. Per gli scenari del "mondo reale" utilizzare le migrazioni EF dovrebbe essere la strada da percorrere, ma forse la causa principale di questo problema è la stessa ...

Aggiornare

La prossima versione includerà il supporto per AttachDBFilename .


Risposta popolare

Potrebbe esserci un diverso file * .mdf già allegato a un database chiamato EfGetStarted2 ... Prova a rilasciare / scollegare quel database e poi riprovare.

È possibile che si verifichino problemi anche se l'utente LocalDB è in esecuzione poiché non dispone delle autorizzazioni corrette per il percorso.



Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché