<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/">
    <channel>
        <title>SQL Server</title>
        <link>http://blogs.ugidotnet.org/PietroLibroBlog/category/SQL Server.aspx</link>
        <description>SQL Server</description>
        <language>it-IT</language>
        <copyright>Pietro Libro</copyright>
        <managingEditor>pietro.libro@libero.it</managingEditor>
        <generator>Subtext Version 2.6.0.0</generator>
        <item>
            <title>EF 6.1 : What&amp;rsquo;s new (3)</title>
            <link>http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/03/27/ef-6.1-whatrsquos-new-3.aspx</link>
            <description>Supporto a “.ToString()” e “String.Concat()”, un esempio:  var queryConcat = from c in db.Vehicles
            where string.Concat(c.EngineSize, c.HP).Equals("1600110")
            select c;

var queryToString = from c in db.Vehicles
            where  c.HP.ToString().Equals("110")
            select c;


 

Abbiamo due Query LINQ che filtrano i dati in base a condizioni su stringhe, la prima “tira fuori” tutti i veicoli dove la concatenazione dei valori delle proprietà “EngineSize” e “HP” è uguale a “1600110”, mentre la seconda esegue un filtro su di un valore intero convertio in stringa. Se proviamo ad eseguire il codice in un ambiente con EF 6.0 otteniamo un’eccezione a runtime in tutti e due i casi:



Con EF 6.1 le query sono eseguite correttamente:



Cosa succede dietro le quinte:

SELECT 
    [GroupBy1].[A1] AS [C1]
    FROM ( SELECT 
        COUNT(1) AS [A1]
        FROM [DomusDotNet].[Vehicles] AS [Extent1]
        WHERE N'1600110' = (CASE WHEN ([Extent1].[EngineSize] IS NULL) THEN N'' ELSE [Extent1].[EngineSize] END +  CAST( [Extent1].[HP] AS nvarchar(max)))
    )  AS [GroupBy1]

SELECT 
    [GroupBy1].[A1] AS [C1]
    FROM ( SELECT 
        COUNT(1) AS [A1]
        FROM [DomusDotNet].[Vehicles] AS [Extent1]
        WHERE N'110' =  CAST( [Extent1].[HP] AS nvarchar(max))
    )  AS [GroupBy1]




Da analizzare il funzionamento di “String.Concat(…)” con SQL Server 2012 per verificare la conversione in SQL con la funzione “nativa SQL” “Concat”.&lt;img src="http://blogs.ugidotnet.org/PietroLibroBlog/aggbug/101829.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Pietro Libro</dc:creator>
            <guid>http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/03/27/ef-6.1-whatrsquos-new-3.aspx</guid>
            <pubDate>Thu, 27 Mar 2014 10:04:00 GMT</pubDate>
            <comments>http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/03/27/ef-6.1-whatrsquos-new-3.aspx#feedback</comments>
            <wfw:commentRss>http://blogs.ugidotnet.org/PietroLibroBlog/comments/commentRss/101829.aspx</wfw:commentRss>
            <trackback:ping>http://blogs.ugidotnet.org/PietroLibroBlog/services/trackbacks/101829.aspx</trackback:ping>
        </item>
        <item>
            <title>EF 6 : Logging &amp;amp; Interception</title>
            <link>http://blogs.ugidotnet.org/PietroLibroBlog/archive/2013/09/04/ef-6-logging-amp-interception.aspx</link>
            <description>   Una delle nuove feature introdotte nella versione 6 di Entity Framework (attualmente in RC) è il supporto al logging dell’SQL generato dal runtime di EF6. A tal fine è sufficiente passare un opportuno delegate alla proporietà Log esposta da DbContext.Database. Per gli esempi riprendiamo lo scenario del post precedente.   Supponiamo di avere il seguente codice:   using (CarContext db = new CarContext())
{
 
    System.Console.WriteLine("Cars in database : {0}", db.Cars.Count());

    ////Add a new car.
    Car car = new Car()
    {
        Brand = "Alfa Romeo",
        Model = "Giulietta"
    };

    db.Cars.Add(car);
    db.SaveChanges();

    System.Console.WriteLine("Cars in database : {0}", db.Cars.Count());               
}



Che banalmente visualizza il numero di auto (Cars) presenti nel  repository, ne aggiunge una e riesegue la conta delle auto registrate. Se volessimo analizzare l’SQL generato un ottimo strumento è sicuramete il SQL Profiler di SQL Server (che non dovrebbe mai mancare quando si lavora con un ORM  ), ma se utilizziamo EF6, ed il nostro obiettivo è semplicemente “scoprire\loggare” l’SQL generato da EF, possiamo modificare il codice precedente aggiungendo dopo la definizione del DbContext, la riga seguente:

 db.Database.Log = Console.Write;

 

Dove la proprietà Log è cosi’ definita:

public Action&amp;lt;string&amp;gt; Log { get; set; }

 


Eseguendo il codice della nostra applicazione dovremmo ottenere una “Console” simile alla seguente:



Di default il log è molto chiaro in quanto ci restituisce il testo SQL del comando, quando è stato eseguito, il tempo impiegato, il tipo di risultato, gli eventuali parametri ed il tipo corrispondente. Possiamo ovviamente cambiare il contenuto e la formattazione del log secondo le nostre esigenze (e non solo) come vedremo piu’ avanti. Per come è definita la proprietà Log, qualsiasi funzione che accetta una stringa puo’ essere utilizzata per scrivere il nostro log. Quindi potremmo utilizzare un metodo tipo il seguente:

public static void Log(string sql)
{
    Console.WriteLine("------------------------------------");
    Console.WriteLine("SQL LOG: {0} ", sql);
    Console.WriteLine("------------------------------------");            
}


 

oppure:

System.IO.StreamWriter streamWriter = new System.IO.StreamWriter (fileStream, System.Text.ASCIIEncoding.ASCII );
db.Database.Log = sql =&amp;gt; streamWriter.Write(sql);


 

Per scrivere il log direttamente su file. Il concetto dovrebbe essere abbastanza chiaro. Vediamo come personalizzare la formattazione del log. 

Database.Log non fa altro che utilizzare un ogetto DatabaseLogFormatter che a sua volta implementa le interfacce IDbCommandInterceptor e IDbInterceptor che sono rispettivamente l’interfaccia che permette di registrare un oggetto che possa ricevere notifiche da parte di Entity Framework quando un comando viene eseguito e l’interfaccia base per tutte le interfacce che permettono di fornire un Interception Point per differenti tipi di operazione.



Quindi, per creare il nostro “Formattatore Custom” non ci resta che ereditare dalla classe DatabaseLogFormatter ed eseguire l’override dei metodi che ci interessano, come nel caso seguente:

public class CustomLogFormatter
    : DatabaseLogFormatter
{
    public CustomLogFormatter(DbContext context, Action&amp;lt;string&amp;gt; writeAction)
        : base(context, writeAction)
    {
    }

    public override void LogCommand&amp;lt;TResult&amp;gt;(
        DbCommand command, DbCommandInterceptionContext&amp;lt;TResult&amp;gt; interceptionContext)
    {
        Write(string.Format("{0}{1}", "===============================================", Environment.NewLine));

        Write(string.Format(
            "Context{2}{0}{2}Command{2}{1}{2}",
            Context.GetType().Name,
            command.CommandText.Replace(Environment.NewLine, ""),
            Environment.NewLine));

        Write(string.Format("{0}{1}", "===============================================", Environment.NewLine));            
    }
}


 

Dove, l’override del metodo LogCommand esegue la formattazione del comando prima che questo sia eseguito da Entity Framework. LogCommand a sua volta  chiama eventualmente il metodo LogParameter per ogni parametro del comando, è necessario eseguire l’override di LogParameter per “customizzare” la formattazione del log dei paramateri. Infine, se vogliamo cambiare la formattazione del risultato, è necessario effettuare l’override di LogResult. Per interrompere l’esecuzione del comando, possiamo utilizzare il metodo :

interceptionContext.SuppressExecution()

 


Nel corpo dell’override di LogCommand. Per vedere in “funzione” il nostro “Formatter” è sufficiente registrare l’istanza di CustomLogFormatter tramite una classe derivata da DbConfiguration presente nello stesso assembly che contiene la definizione del DbContext:

public class MyDbConfiguration : DbConfiguration
{
    public MyDbConfiguration()
    {
        SetDatabaseLogFormatter(
            (context, writeAction) =&amp;gt; new CustomLogFormatter(context, writeAction));
    }
}


Eseguendo, otteniamo il “nostro” log:



Per approfondimenti:

Entity Framework Codeplex

One Unicorn: EF6 SQL Logging&lt;img src="http://blogs.ugidotnet.org/PietroLibroBlog/aggbug/101658.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Pietro Libro</dc:creator>
            <guid>http://blogs.ugidotnet.org/PietroLibroBlog/archive/2013/09/04/ef-6-logging-amp-interception.aspx</guid>
            <pubDate>Wed, 04 Sep 2013 15:15:00 GMT</pubDate>
            <comments>http://blogs.ugidotnet.org/PietroLibroBlog/archive/2013/09/04/ef-6-logging-amp-interception.aspx#feedback</comments>
            <wfw:commentRss>http://blogs.ugidotnet.org/PietroLibroBlog/comments/commentRss/101658.aspx</wfw:commentRss>
            <trackback:ping>http://blogs.ugidotnet.org/PietroLibroBlog/services/trackbacks/101658.aspx</trackback:ping>
        </item>
        <item>
            <title>OCA, Sync Framework e SQL Server 2008</title>
            <link>http://blogs.ugidotnet.org/PietroLibroBlog/archive/2011/08/21/oca-e-sync-framework-e-sql-server-2008.aspx</link>
            <description>   Ultimamente mi sono trovato a sviluppare un’applicazione con la necessità di sincronizzare i dati locali con un’istanza di SQL Server 2008. Generalmente parlando, le applicazioni OCA (occasionally connected application) permettono di utilizzare un’applicazione client che fa uso di dati memorizzati in una base di dati locale che periodicamente è sincronizzata  con un database centrale disposto su un server.  Il processo di sincronizzazione non è mai stato un task banale (almeno nel caso bidirezionale), è penso che ognuno di noi, almeno una volta nella vita da sviluppatore si sia imbattuto in questo tipo di operazione. Fino a qualche tempo fa, spesso si creavano soluzioni ad hoc, funzionanti, ma magari non performanti o comunque a basso riuso. Per fortuna (tra l’altro da diverso tempo ) abbiamo a disposizione il  Microsoft Sync Framework (che personalmente, fino ad oggi non ho mai avuto occasione di utilizzare in modo proficuo), una piattaforma  che fornisce agli sviluppatori gli strumenti necessari per aggiungere funzionalità di sincronizzazione ad applicazioni, servizi e dispositivi. Nello specifico del post,  ci concentreremo sul funzionamento relativo alla sincronizzazione di database, ma il Microsoft Sync Framework mette a disposizione i Synchronization Services per File Systems ed i Synchronization Services per FeedSync. La versione presente in Visual Studio 2010 è la 2.1, ma è possibile scaricare la versione 4.0 CTP , costruita sulla versione 2.1, con supporto al protocollo   “OData + Sync” per lo sviluppo più facile di applicazioni OCA su qualsiasi piattaforma capace di eseguire il caching dei dati oltre alla sincronizzazione di dati memorizzati su SQL Server o SQL Azure.  Durante il processo di sincronizzazione l’aspetto più complesso è sicuramente la tracciatura dei cambiamenti (ovvero i relativi INSERT, UPDATE e DELETE eseguiti sul database Client e\o Server), altrimenti, ogni volta che l’utente si collega al database centrale per la sincronizzazione dei dati deve necessariamente eseguire il download di tutte le informazioni  (in situazioni di connessioni lente o non affidabili potrebbe essere un problema di costi e\o tempi). Un metodo naive per eseguire il tracking dei cambiamenti è l’utilizzo di trigger o l’utilizzo di campi rowversion aggiunte alle tabelle soggette a sincronizzazione. Per la cancellazione dei record il discorso è leggermente diverso in quanto è necessario memorizzare le informazioni in una tabella separata (tombstone table) . Ovviamente, questa “metodologia” comporta alcuni svantaggi:     - E’ necessario introdurre modifiche allo schema della base di dati     - I trigger comportano problemi di performance    - Scrittura della logica per rowversion e cancellazione delle righe   Se utilizziamo SQL Server 2008 come database centrale, possiamo evitare i problemi precedentemente esposti in quanto in questa versione è stata introdotto il “SQL Server 2008 Change Tracking”, un meccanismo il cui utilizzo si “riduce” a marcare le tabelle da monitorare,  tracciando automaticamente le varie INSERT, UPDATE e DELETE, così da fornire gli opportuni cambiamenti ai client che richiedono di sincronizzarsi rispetto all’ultima operazione di sincronizzazione. Utilizzando il Sync Framework abbiamo questo supporto in modo nativo ed integrato in Visual Studio 2010 senza apportare modifiche allo schema del database, senza trigger e senza dover scrivere codice SQL di logica (maggiori dettagli su MSDN).   Proviamo a chiarire i concetti esposti con un esempio. Prendiamo in considerazione un database con un schema del tipo in figura:    Che descrive un semplicissimo database di un possibile e-commerce (Cliente, Acquisto e Prodotto). Il nostro scopo è sincronizzare i dati tra un client (una piccola applicazione stand-alone di esempio) che utilizza una database locale di SQL Server Compact 3.5 (od eventualmente 4.0 con le apposite modifiche) ed il database centrale presente in un’istanza di SQL Server 2008.  Creiamo un nuovo progetto Console o Windows Form (nel nostro caso) di Visual Studio 2010 a cui andiamo ad aggiungere il necessario per fornire l’accesso alla sincronizzazione dei dati. Dopo la creazione del progetto, aggiungiamo un nuovo item (dalla sezione Data) “Local Database Cache”:    A questo punto verrà visualizzata una nuova finestra nella quale andremo a specificare i parametri di connessione lato server e lato client:    Se  stiamo utilizzando una connessione verso un database di SQL Server 2008, il Check “User SQL Server change Tracking” dovrebbe essere abilitato, e spuntando la voce, abbiamo la possibilità di sfruttare il Change Tracking integrato. Ancora, possiamo scegliere se l’operazione di sincronizzazione avverrà all’interno di un’unica transazione (se vogliamo che tutti  o nessuno dei dati siano scaricati) oppure (secondo dello scenario)  se vogliamo scaricare\caricare ad ogni sincronizzazione quanti più dati possibili. Restando nella finestra, sono presenti delle liste a discesa che permettono di scegliere, all’interno della nostra soluzione di Visual Studio il progetto lato client ed il progetto lato server. Nel nostro caso lasciamo la voce selezionata di Default, e quindi consideriamo il progetto precedentemente creato. E’ arrivato il momento di scegliere le tabelle che faranno parte della nostra cache di dati locale: l’operazione è molto semplice in quanto è sufficiente utilizzare il bottone con la dicitura Add  in fondo a sinistra della ListBox presente:     Nella finestra “Configure Tables for Offline Use” è possibile selezionare le tabelle che vogliamo sincronizzare con i nostri client. Per ognuna di essa possiamo scegliere se ogni volta vogliamo scaricare l’interno contenuto della tabella (come durante la prima sincronizzazione)  o se  ogni successiva sincronizzazione sial di tipo incrementale. Nel caso stessimo utilizzando una versione diversa da SQL Server 2008 (ad esempio SQL Server 2005) come database centrale, non avendo a disposizione il supporto nativo al Change Tracking avremmo dovuto  specificare delle Stored Procedure ad-hoc nei campi Compare update using, Compare insert using e Move deleted items to a supporto della logica di sincronizzazione:    A questo punto il gioco è quasi finito, in quanto premendo su OK, al progetto verranno aggiunti tutti i file e riferimenti necessari al funzionamento. Piccola nota: nella schermata precedente premendo il link Show Code Example viene visualizzata una finestra di dialogo con del codice di esempio (molto comodo se si utilizza il Sync Framework per la prima volta) per effettuare la sincronizzazione dei dati:    A questo punto viene avviata la prima sincronizzazione con la creazione del file “.sdf” di SQL Server Compact (ricordiamo per default nella versione 3.5).  Dopo qualche secondo è visualizzata una nuova schermata in cui possiamo scegliere se utilizzare un DataSet o un file EDM (Entity Data Model) per il nostro Object Model as Data Model. Partiamo con un semplice DataSet (  ):    Nelle schermate che si susseguono andiamo a configurare il nostro DataSet  tipizzato con tutte le tabelle che servono al funzionamento della nostra applicazione client. Notiamo che oltre alle tabelle originali troviamo tre tabelle __syncArticles, _syncSubscriptions e __syncTransactioncs necessarie per le operazioni di sincronizzazione, ma possiamo tranquillamente ignorarle. Alla fine del Wizard, il nostro DataSet dovrebbe assomigliare a qualcosa di questo tipo:    Bene. Supponendo di aver aggiunto alla nostra soluzione una Windows Form contenente una griglia e due bottoni (Synchronize e Close) come nella figura seguente:    Nell’handler dell’evento click del bottone Synchronize possiamo scrivere del codice tipo:     LocalCacheSyncAgent syncAgent = new LocalCacheSyncAgent();syncAgent.Product.SyncDirection = Microsoft.Synchronization.Data.SyncDirection.Bidirectional;Microsoft.Synchronization.Data.SyncStatistics syncStats = syncAgent.Synchronize();////Server -&amp;gt; ClientStringBuilder sb = new StringBuilder();sb.AppendLine(string.Format("Download Changes: {0}", syncStats.DownloadChangesApplied));sb.AppendLine(string.Format("Download Failed: {0}", syncStats.DownloadChangesFailed));sb.AppendLine(string.Format("Upload Changes: {0}", syncStats.UploadChangesApplied));sb.AppendLine(string.Format("Upload Failed: {0}", syncStats.UploadChangesFailed));sb.AppendLine(string.Format("Start Time: {0}", syncStats.SyncStartTime));sb.AppendLine(string.Format("Complete Time: {0}", syncStats.SyncCompleteTime));MessageBox.Show(sb.ToString());


Dove come prima operazione creiamo un’istanza di LocalCacheSyncAgent, ovvero l’engine che si occuperà di effettuare materialmente il lavoro di sincronizzazione. Impostiamo tramite la proprietà SyncDirection una sincronizzazione di tipo Bidirezionale per la tabella Product. Altre possibili opzioni sono:


  - Download, sincronizzazione unidirezionale Server –&amp;gt; Client 

  - Upload, sincronizzazione unidirezionale Client –&amp;gt; Server 

  - Snapshot, durante la sincronizzazione viene scaricato un insieme di dati,  aggiornato completamente ad ogni sincronizzazione. 


A questo punto non resta che invocare il metodo Synchronize del nostro “Agent” che restituisce un’istanza di SyncStatistics contenente le informazioni sull’esito della sincronizzazione, che “raccogliamo” mediante uno StringBuilder e mostriamo all’utente al termine delle operazioni con una semplice MessageBox:



Sopra è mostrato il risultato della prima sincronizzazione. Aggiungendo una riga in Product nella tabella locale (client), e sincronizzando nuovamente dovremmo ottenere un risultato di questo tipo:



Dove chiaramente si evince come sia stato eseguito l’upload di dati verso il server. Ok, ma ovviamente non tutte le tabelle escono col buco, di conseguenza bisogna prepararsi ad ogni evenienza, ovvero alla gestione di possibili conflitti tra dati presenti su Client e Server durante la sincronizzazione. Modifichiamo la parte iniziale del codice precedente in questo modo:


  LocalCacheSyncAgent syncAgent = new LocalCacheSyncAgent();syncAgent.Product.SyncDirection = Microsoft.Synchronization.Data.SyncDirection.Bidirectional;////-----LocalCacheClientSyncProvider localProvider = syncAgent.LocalProvider as LocalCacheClientSyncProvider;LocalCacheServerSyncProvider serverProvider = syncAgent.RemoteProvider as LocalCacheServerSyncProvider;localProvider.ApplyChangeFailed += new EventHandler&amp;lt;Microsoft.Synchronization.Data.ApplyChangeFailedEventArgs&amp;gt;(localProvider_ApplyChangeFailed);serverProvider.ApplyChangeFailed += new EventHandler&amp;lt;Microsoft.Synchronization.Data.ApplyChangeFailedEventArgs&amp;gt;(serverProvider_ApplyChangeFailed);////-----Microsoft.Synchronization.Data.SyncStatistics syncStats = syncAgent.Synchronize();...


Dove attraverso istanze di LocalCacheClientSyncProvider e LocalCacheServerSyncProvicer ci sottoscriviamo agli eventi per la gestione dei conflitti, ApplyChangedFailed:


  if(e.Conflict.ConflictType == Microsoft.Synchronization.Data.ConflictType.ClientInsertServerInsert){    DataTable clientChange = e.Conflict.ClientChange;    DataTable serverChange = e.Conflict.ServerChange;    FrmConflicts frmConflicts = new FrmConflicts();    frmConflicts.SetDataSource(clientChange, serverChange);    frmConflicts.ShowDialog(this);    e.Action = Microsoft.Synchronization.Data.ApplyAction.RetryWithForceWrite;}if (e.Conflict.ConflictType == Microsoft.Synchronization.Data.ConflictType.ErrorsOccurred){    MessageBox.Show(e.Conflict.ErrorMessage);    e.Action = Microsoft.Synchronization.Data.ApplyAction.Continue;}


Nel codice intercettiamo due dei possibili conflitti che possono verificarsi: nel caso di conflitto dovuto ad  Insert su Client e Server (ad esempio su client e server viene aggiunto uno stesso prodotto), mostriamo all’utente tramite una seconda Windows Form (FrmConflicts) il dati che creano il problema , e dopo forziamo la scrittura (causando di fatto una duplicazione dei valori all’interno della tabella Product, ovviamente possono\devono essere considerate altre strategie scelte eventualmente dall’utente). Nel caso di conflitto dovuto ad errore non predicibile mostriamo (in modo molto brutale ) un MessageBox contenente informazioni di errore (in un’applicazione reale questo dovrebbe essere evitato in quanto potrebbero essere visualizzate informazioni sensibili per la sicurezza del sistema) e tentiamo di continuare la sincronizzazione dei dati.

Se invece di utilizzare un DataSet volessimo utilizzare Entity Framework, il gioco è semplice, basta utilizzare il Wizard dell’Entity Data Model per costruire un modello da un database già presente (il file .sdf) . Nello specifico caso, avremmo qualcosa di questo tipo:



Le operazioni di sincronizzazione a questo punto non sono più un problema (o almeno si spera ).&lt;img src="http://blogs.ugidotnet.org/PietroLibroBlog/aggbug/100287.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Pietro Libro</dc:creator>
            <guid>http://blogs.ugidotnet.org/PietroLibroBlog/archive/2011/08/21/oca-e-sync-framework-e-sql-server-2008.aspx</guid>
            <pubDate>Sun, 21 Aug 2011 14:08:00 GMT</pubDate>
            <comments>http://blogs.ugidotnet.org/PietroLibroBlog/archive/2011/08/21/oca-e-sync-framework-e-sql-server-2008.aspx#feedback</comments>
            <slash:comments>2</slash:comments>
            <wfw:commentRss>http://blogs.ugidotnet.org/PietroLibroBlog/comments/commentRss/100287.aspx</wfw:commentRss>
            <trackback:ping>http://blogs.ugidotnet.org/PietroLibroBlog/services/trackbacks/100287.aspx</trackback:ping>
        </item>
        <item>
            <title>Confronto di schemi di database in Visual Studio</title>
            <link>http://blogs.ugidotnet.org/PietroLibroBlog/archive/2009/12/26/confronto-di-schemi-di-database-in-visual-studio.aspx</link>
            <description>   Da quando ho avuto la fortuna di poter installare Visual Studio Team System, per gestire le modifiche sui database di SQL Server utilizzo il tool integrato “Nuovo confronto schema” raggiungibile dal menu dati di Visual Studio. Il tool si presenta come nello screenshot seguente (in questo caso la “versione italiana”):     A questo punto possiamo scegliere i database su cui eseguire il confronto degli schemi e premere “OK”. Secondo della complessità dei database su cui viene eseguito il confronto, la procedura potrebbe impiegare qualche minuto prima di terminare. Completato il processo, verrà visualizzata una schermata in cui viene riepilogato lo stato dei due database:      Con qualche click del mouse è possibile indicare quali oggetti (tabelle, colonne, utenti…) bisognerà creare, aggiornare o eliminare nei due database. A questo punto è possibile eseguire direttamente l’aggiornamento sul database di destinazione o salvare lo script di aggiornamento su file:     Avendo installato sulla mia macchina due istanze di SQL Server 2005, una di “Sviluppo” ed una di “Produzione”, dopo ogni release, in caso di modifiche al database, tenere aggiornate le due istanze è veramente semplice. Spesso mi sono trovato ad utilizzare il prodotto “SQL Delta”, ma la comodità di avere tutti gli strumenti integrati in un unico ambiente di sviluppo è un’altra cosa.&lt;img src="http://blogs.ugidotnet.org/PietroLibroBlog/aggbug/97766.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Pietro Libro</dc:creator>
            <guid>http://blogs.ugidotnet.org/PietroLibroBlog/archive/2009/12/26/confronto-di-schemi-di-database-in-visual-studio.aspx</guid>
            <pubDate>Sat, 26 Dec 2009 17:47:00 GMT</pubDate>
            <comments>http://blogs.ugidotnet.org/PietroLibroBlog/archive/2009/12/26/confronto-di-schemi-di-database-in-visual-studio.aspx#feedback</comments>
            <wfw:commentRss>http://blogs.ugidotnet.org/PietroLibroBlog/comments/commentRss/97766.aspx</wfw:commentRss>
            <trackback:ping>http://blogs.ugidotnet.org/PietroLibroBlog/services/trackbacks/97766.aspx</trackback:ping>
        </item>
        <item>
            <title>Shrink, BackUp e ...SSIS</title>
            <link>http://blogs.ugidotnet.org/PietroLibroBlog/archive/2009/08/26/shrink-backup-e-.ssis.aspx</link>
            <description>  
Uno dei task più frequenti nella manutenzione dei database (nel caso SQL Server) è quello di  effettuarne lo Shrink (a riguardo, suggerisco di leggere il commento lasciato da Davide Mauri) ed il BackUp. Finchè le operazioni riguardano un solo database possiamo completare il task utilizzando, ad esempio, SQL Server Management Studio. Nel caso in cui le suddette operazioni debbano essere effettuate su più database la "faccenda si complica" (più che altro diventa ripetitiva) e possiamo    
risolvere il problema creando un package SSIS (SQL Server Integration Services). Premetto che googlando si possono trovare diverse soluzioni, utilizzando anche lo stesso sistema. Per iniziare, apriamo Visual Studio (2008 Professional nel mio caso) e partiamo con il creare un nuovo progetto "Integration Services Project" (ovviamente per visualizzare questo template è necessario che tutti i componenti relativi siano correttamente installati e configurati) 
 
Creiamo una nuova connessione al server sql interessato nel "Connection Managers" (tasto destro-&amp;gt;"New OLE DB Connection...") 
 
Se si vuole, dopo la creazione della connessione è sempre possibile rinominare la stessa. 
A questo punto, nel "Control Flow" non ci resta che trascinare due Task presenti nel Tab    
"Maintenance Plan Tasks" della Toolbox, in particolare "Shrink Database Task" e "Back Up Database Task". Per impostare le opzioni ed i database su cui eseguire le operazioni è sufficiente un doppio click sui task aggiunti. Ad esempio cliccando due volte su "Shrink Database Task", otteniamo: 
 
Effettuiamo la stessa operazione sul task relativo al BackUp. A questo punto abbiamo quasi terminato, ma vogliamo che al completamento delle operazioni venga inviata all'amministratore una e-mail di notifica. Potremmo utilizzare "Send Mail Task", ma ha delle limitazioni (tra lequali non è possibile specificare le credenziali d'accesso al server SMTP, ma utilizza l'autenticazione di Windows), per questo, aggiungiamo uno "Script Task" nel nostro "Data Flow". Solito doppio click, e nella finestra visualizzata premiamo    
sul bottone con la dicitura "Edit Script...". 
 
Verrà visualizzata una finestra di Visual Studio in cui possiamo scrivere il codice (C#) per l'invio dell'e-mail. Per chi è abituato ad usare Visual Basic, nella finestra delle proprietà del Task è possibile scegliere quale linguaggio utilizzare (nota: nella versione 2005 non era possibile scegliere tra i due linguaggi). Prima di iniziare a scrivere è necessario aggiungere un riferimento all'assembly System.Net.dll al progetto. Scriviamo del codice simile al seguente: 


   1:  System.Net.Mail.MailMessage message = new System.Net.Mail.MailMessage();
   2:  message.From = new System.Net.Mail.MailAddress("indirizzo@dominio.it");
   3:  message.To.Add (new System.Net.Mail.MailAddress("amministratore@dominio.it"));
   4:  message.Body =string.Format ("BackUp dei database completato ({0:d})",DateTime.Now );
   5:  message.Subject ="Backup"; 
   6:   
   7:  try
   8:  {
   9:      System.Net.Mail.SmtpClient smtp = new System.Net.Mail.SmtpClient("smtp.dominio.it");
  10:      smtp.Credentials = new NetworkCredential("username", "password");
  11:      smtp.Send(message); 
  12:   
  13:      Dts.TaskResult = (int)ScriptResults.Success;
  14:  }
  15:  catch (Exception ex)
  16:  {
  17:      Dts.Log(ex.Message, 123, null);
  18:      Dts.TaskResult = (int)ScriptResults.Failure;
  19:  } 

Tramite un costrutto Try...Catch catturiamo eventuali eccezioni ed indichiamo  il successo o il fallimento del task. 
Ogni volta che abbiamo la necessità di utilizzare questo Package, non è necessario aprire  un'istanza di Visual Studio, ma è possibile utilizzare l'utility "DTExec.exe"  da riga di comando (ad esempio, DTExec.exe /FILE "package.dtsx". (E' possibile trovare il package nella directory "bin" del progetto)
Technorati Tag: SSIS,Backup,Shrink&lt;img src="http://blogs.ugidotnet.org/PietroLibroBlog/aggbug/96923.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Pietro Libro</dc:creator>
            <guid>http://blogs.ugidotnet.org/PietroLibroBlog/archive/2009/08/26/shrink-backup-e-.ssis.aspx</guid>
            <pubDate>Wed, 26 Aug 2009 09:30:29 GMT</pubDate>
            <comments>http://blogs.ugidotnet.org/PietroLibroBlog/archive/2009/08/26/shrink-backup-e-.ssis.aspx#feedback</comments>
            <slash:comments>2</slash:comments>
            <wfw:commentRss>http://blogs.ugidotnet.org/PietroLibroBlog/comments/commentRss/96923.aspx</wfw:commentRss>
            <trackback:ping>http://blogs.ugidotnet.org/PietroLibroBlog/services/trackbacks/96923.aspx</trackback:ping>
        </item>
        <item>
            <title>SQL Server 2005 Build List</title>
            <link>http://blogs.ugidotnet.org/PietroLibroBlog/archive/2009/08/22/sql-server-2005-build-list.aspx</link>
            <description>Al seguente indirizzo http://www.sqlservercentral.com/articles/Administration/2960/ è presente un articolo aggiornato al 17/06/2009 da Steve Jones con l'elenco delle Build relative a SQL Server 2005. Per ogni build è presente il link alla relativa pagina di descrizione. Sono ben messe in evidenza (in testa all'articolo) le Major Builds (RTM, SP1, SP2, SP3).&lt;img src="http://blogs.ugidotnet.org/PietroLibroBlog/aggbug/96907.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Pietro Libro</dc:creator>
            <guid>http://blogs.ugidotnet.org/PietroLibroBlog/archive/2009/08/22/sql-server-2005-build-list.aspx</guid>
            <pubDate>Sat, 22 Aug 2009 11:36:36 GMT</pubDate>
            <comments>http://blogs.ugidotnet.org/PietroLibroBlog/archive/2009/08/22/sql-server-2005-build-list.aspx#feedback</comments>
            <wfw:commentRss>http://blogs.ugidotnet.org/PietroLibroBlog/comments/commentRss/96907.aspx</wfw:commentRss>
            <trackback:ping>http://blogs.ugidotnet.org/PietroLibroBlog/services/trackbacks/96907.aspx</trackback:ping>
        </item>
    </channel>
</rss>