25

Sto lavorando a un progetto che utilizza Entity Framework 4.1 per mantenere i nostri vari oggetti nel database (prima il codice).Entity Framework 4.1 Il modello di backup del contesto è cambiato da quando il database è stato creato, subito dopo la creazione del DB

Sto testando in Visual Studio con un DB SQL Express locale e il nostro server Jenkins distribuisce codice impegnato su un server di prova. Quando ciò accade, modifica temporaneamente la stringa di connessione locale per puntare al server DB di test ed eseguo un test dell'unità per ricreare il database di test in modo che corrisponda alle nostre ultime entità, ecc.

Ho notato di recente i nostri test server sta dando questo errore:

Il modello di backup del contesto "EntityFrameworkUnitOfWork" è stato modificato da quando il database è stato creato. Eliminare o aggiornare manualmente il database o chiamare Database.SetInitializer con un'istanza IDatabaseInitializer. Ad esempio, la strategia DropCreateDatabaseIfModelChanges eliminerà e ricreerà automaticamente il database e facoltativamente lo seminerà con nuovi dati.

Questo di solito è un'indicazione che il nostro codice è cambiato e ho bisogno di eseguire il test dell'unità per ricreare il database. Tranne che l'ho appena fatto! Non credo che ci sia qualcosa di sbagliato nel nostro processo di distribuzione: le DLL sul server di test sembrano essere le stesse versioni del mio ambiente locale. Ci sono altre impostazioni o fattori ambientali che possono causare questo errore sul modello che è cambiato da quando è stato creato il database?

Sono nuovo qui - grazie per qualsiasi aiuto!

+1

Si può usare il metodo 'System.Data.Entity.Infrastructure.EdmMetadata.TryGetModelHash (YourDbContext)' per ottenere ModelHash e provare a farlo sul PC locale e sul server di test per vedere se sono diversi? – Marc

+0

Hai eseguito uno strumento personalizzato per rigenerare il contesto o POCO dopo aver rigenerato il database? –

+1

@Marc Sì, gli hash sembrano essere diversi. – DaveBeta

risposta

25

L'errore visualizzato indica che l'hash del modello memorizzato nella tabella EdmMetadata è diverso dall'hash del modello calcolato dal modello nell'applicazione.Poiché stai eseguendo la creazione di database da un'applicazione diversa (la tua applicazione di sviluppo) è possibile che questi due differiscano. Un consiglio semplice è: non utilizzare applicazioni diverse per la creazione del database e lasciare che l'applicazione principale crei il database (automaticamente o, ad esempio, con alcune interfacce di amministrazione).

Come ulteriore opzione si dovrebbe essere in grado di disattivare questo controllo completamente rimuovendo la Convenzione incaricata di questi controlli:

modelBuilder.Conventions.Remove<IncludeMetadataConvention>(); 

modello hash calcolo è dipendente da entità correnti nella vostra applicazione (qualsiasi risultato semplice cambiamento diverso hash del modello) e versioni/manifest del server database. Ad esempio, un modello distribuito su SQL server 2005 e 2008 avrà un hash del modello diverso (Express vs. Full o 2008 vs 2008 R2 non dovrebbe comportare un hash di modello diverso).

+0

Abbiamo una versione OS diversa sul desktop e sul server, e abbiamo anche un paio di versioni diverse di SQL Server perché sto usando SQL Express localmente ma non su UAT. Se è solo un dato di fatto che queste differenze di piattaforma causeranno un diverso hash di 'EdmMetadata', sono lieto di disabilitare semplicemente la creazione/verifica dell'hash rimuovendo la convenzione. Grazie! – DaveBeta

+0

'Avviso 'System.Data.Entity.Infrastructure.IncludeMetadataConvention' è obsoleto: 'IncludeMetadataConvention non è più utilizzato. EdmMetadata non è incluso nel modello. ora viene utilizzato per rilevare le modifiche nel modello. " \t '** 2013 ** La risposta non è più rilevante in EF4 – ppumkin

+0

@ppumkin: la risposta era pertinente prima di EF4.3 –

2

Il codice Entity Framework crea innanzitutto una tabella denominata EdmMetadata. Mantiene un hash del tuo modello attuale. Una volta eseguita l'applicazione, EF controlla se il modello utilizzato è lo stesso del modello che il db 'conosce'.

Se si desidera eseguire la migrazione del database, suggerisco di utilizzare EF Code first migrations sebbene sia ancora un alfa.

Se non si desidera utilizzare le migrazioni è possibile:

gestire la modifica dello schema manualmente - che significa spostare il contenuto della tabella EdmMetadata al server di prova con tutti i cambiamenti

o

impostare l'inizializzatore db su DropCreateDatabaseIfModelChanges (o meglio qualcosa derivato da esso e utilizzare il metodo Seed() per scrivere i dati iniziali). Per impostare l'initialzer o chiamare Database.SetInitializer() su richiesta avviare o utilizzare i appsettings

<add key="DatabaseInitializerForType Fully.Qualified.Name.Of.Your.DbContext," value="Fully.Qualified.Name.Of.The.Initializer" /> 
+1

Grazie per quello. Il mio mistero era più legato al fatto che ho due server di applicazioni che, per quanto posso dire, sono identici - certamente le DLL sono identiche, eppure entrambi sembrano pensare che il DB creato dall'altro sia "diverso". Ho scoperto che eliminando la tabella EdmMetadata posso eliminare l'errore ed entrambe le applicazioni sembrano funzionare con lo stesso database felicemente. Questo sembra sbagliato! – DaveBeta

+0

Sto avendo un problema simile al momento della distribuzione, una semplice ricompilazione e ridistribuzione della dll (assolutamente nessuna modifica) e risolve il problema – JarrettV

3

Questo potrebbe aiutare e il link al blog di Scott G sarà sicuramente una soluzione al vostro problema controllare questa domanda link

Edit 1: questo è il link to Scott G blog

Edit 2: si può anche verificare se si utilizza this prima un database sul server di integrazione

Edit 3: questo è un more detailed answer come quello di Scott G

+0

@Il ragazzo con il downvote: Hai almeno provato a controllare le risposte? –

9

Ciò può accadere a causa della riflessione che ordina le differenze tra diverse piattaforme. Per verificare, è possibile utilizzare l'API EdmxWriter per confrontare EDMX da entrambi gli ambienti. Se una delle tabelle ha un ordinamento di colonne diverso, allora questo è il problema.

Per risolvere il problema, è possibile modificare il modo in cui il database di test viene aggiornato in modo che venga aggiornato dal server di prova anziché dalla casella locale.

Stiamo andando a risolvere questo problema nella prossima versione.

+0

Questa può essere una differenza anche in base alla configurazione di build? es. debug vs release? – JarrettV

3

I due server che eseguono l'applicazione eseguono sistemi operativi diversi (o service pack?). Sembra che lo SHA256CryptoService utilizzato possa generare una PlatformNotSupportedException che ne causa il fallback su un altro metodo.

http://msdn.microsoft.com/en-us/library/system.security.cryptography.sha256cryptoserviceprovider.sha256cryptoserviceprovider.aspx

// System.Data.Entity.Internal.CodeFirstCachedMetadataWorkspace 
private static SHA256 GetSha256HashAlgorithm() 
{ 
    SHA256 result; 
    try 
    { 
    result = new SHA256CryptoServiceProvider(); 
    } 
    catch (PlatformNotSupportedException) 
    { 
    result = new SHA256Managed(); 
    } 
    return result; 
} 

Si può essere in grado di testare questo utilizzando riflessione per richiamare i seguenti 2 metodi (interni/privati) su ciascun server.

MetaDataWorkspace.ToMetadataWorkspace(DbDatabaseMapping, Action<string>) 
CodeFirstCachedMetadataWorkspace.ComputeSha256Hash(string xml); 
+0

Torna a una versione gestita che dovrebbe produrre lo stesso risultato. – JarrettV

6

Nell'approccio code-first, l'SSDL viene generato durante l'esecuzione del codice. Una delle informazioni incluse nell'SSDL generato è il nome del provider utilizzato in DbConnection. Come hai detto, ti stai collegando a diversi motori di database, quindi devi utilizzare due diversi provider. Questo modifica completamente l'output della funzione di hashing.

Il codice qui sotto è stato estratto dal gruppo EntityFramework:

using (XmlWriter writer = XmlWriter.Create(output, settings)) 
{ 
    new SsdlSerializer().Serialize(database, providerInfo.ProviderInvariantName, providerInfo.ProviderManifestToken, writer); 
} 
+0

Vedo una differenza tra il debug e il rilascio, non dal provider che cambia – JarrettV

+0

Sebbene questo non risponda alla mia domanda, risponde alla domanda originale. Ecco la tua taglia. – JarrettV

0

Ho solo accidentalmente rinominato il mio file mdf e ottenuto questo errore. Quindi guarda anche questo.

Problemi correlati