Se fossi io (quando sono io...):
Non vuoi particolarmente provare a far funzionare i file di database copiandoli e allegandoli:ci sono ragioni per cui potresti volerlo, ma credo che queste siano eccezioni piuttosto che regole.
Di conseguenza, quello che devi fare è creare uno script per la creazione del database, ovvero usare SQL DDL per creare il database e le tabelle e tutte le altre cose nel tuo schema.
Praticamente tutto ciò di cui hai bisogno per consentirti di farlo sono i diritti appropriati sull'istanza del server e quindi una stringa di connessione (che probabilmente puoi creare a parte il nome del server/istanza).
Da qui:
- Esiste un database? Altrimenti crealo.
- Se esiste un database, è la versione dello schema corretta? Se è troppo basso, aggiornalo o avvisa l'utente e torna indietro con grazia a seconda di come vuoi che le cose funzionino. Se troppo alto, torna indietro e avvisa che è necessaria una versione aggiornata dell'applicazione
- Tutto è come dovrebbe essere, continua.
Dal punto di vista del codice:metodo per determinare se esiste un database; metodo per creare un database standard "vuoto" con una tabella delle versioni e un numero di versione pari a 0; metodi per portare lo schema alla versione corrente eseguendo il DDL appropriato (codifichiamo il nostro in C# perché offre maggiore flessibilità ma è possibile eseguire ugualmente gli script DDL in sequenza).
Esiste:
public virtual bool Exists()
{
bool exists = false;
string masterConnectionString = this.CreateConnectionString(this.Server, this.FailoverServer, "master");
this.DBConnection.ConnectionString = masterConnectionString;
this.DBConnection.Open();
try
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = this.DBConnection;
cmd.CommandText = "SELECT COUNT(name) FROM sysdatabases WHERE name = @DBName";
cmd.Parameters.AddWithValue("@DBName", this.DBName);
exists = (Convert.ToInt32(cmd.ExecuteScalar()) == 1);
}
finally
{
this.DBConnection.Close();
}
return exists;
}
Crea un nuovo database:
public virtual void CreateNew()
{
string createDDL = @"CREATE DATABASE [" + this.DBName + "]";
this.BuildMasterConnectionString();
this.DBConnection.Open();
try
{
this.ExecuteSQLStmt(createDDL, this.DefaultSQLTimeout, null);
}
finally
{
this.DBConnection.Close();
}
createDDL = @"
CREATE TABLE AAASchemaVersion
(
Version int NOT NULL,
DateCreated datetime NOT NULL,
Author nvarchar(30) NOT NULL,
Notes nvarchar(MAX) NULL
);
ALTER TABLE AAASchemaVersion ADD CONSTRAINT PK_Version PRIMARY KEY CLUSTERED
(
Version
);
INSERT INTO AAASchemaVersion
(Version, DateCreated, Author, Notes)
VALUES
(0, GETDATE(), 'James Murphy', 'Empty Database')
";
this.BuildConnectionString();
this.ConnectionString += ";pooling=false";
this.DBConnection.Open();
try
{
this.ExecuteSQLStmt(createDDL, this.DefaultSQLTimeout, null);
}
catch (Exception ex)
{
throw new Exception("Exception while creating / initialising AAASchemaVersion", ex);
}
finally
{
this.DBConnection.Close();
}
}
Il codice di aggiornamento è un po' più complesso ma fondamentalmente esegue cose come questa:
CREATE TABLE AuditUser
(
ID int IDENTITY(1,1) NOT NULL,
UserSourceTypeID tinyint NOT NULL,
DateCreated smalldatetime NOT NULL,
UserName nvarchar(100) NOT NULL
);
ALTER TABLE AuditUser
ADD CONSTRAINT
PK_AuditUser PRIMARY KEY CLUSTERED
(
ID
),
CONSTRAINT [FK_AuditUser_UserSourceType] FOREIGN KEY
(
UserSourceTypeID
) REFERENCES UserSourceType (
ID
);
Tutto racchiuso in una transazione per aggiornamento, in modo che se l'aggiornamento non riesce dovresti lasciare il database in uno stato noto.
Perché farlo in questo modo (nel codice, che non è privo di prove?) Bene, il risultato finale è un alto grado di sicurezza che lo schema con cui sta parlando la tua app è lo schema con cui la tua app si aspetta di parlare ... tabelle giuste, colonne giuste (nell'ordine giusto, che siano del tipo giusto e della lunghezza giusta), ecc, ecc. e che questo continuerà ad essere il caso nel tempo.
Mi scuso se è un po' lungo, ma è qualcosa che mi appassiona molto...