Migrare progetti ad un altro Framework

A meno che non siate della vecchia scuola e tutto va in un unico progetto della solution, ormai anche banali solution possono avere una decina di progetti.

In questo caso, la migrazione ad un’altra versione del Framework, per necessità o su richiesta del cliente, può essere, oltre che noioso (oltre a dover entrare in ogni progetto per cambiare il FW dobbiamo pure confermare la nostra scelta) anche prono a qualche errore in caso ci dimentichiamo di “passare” su qualche progetto.

Ovviamente non siamo i soli ad avere questo problema e qualcuno ha già scritto l’extension per noi: Target Framework Migrator fa proprio quello che ci serve e se volete partecipare allo sviluppo il codice sorgente è su GitHub.

Happy Migrations! Winking smile

Sql Server e COLLATE

In questi giorni mi sono trovato dover fare query tra database differenti e mi si è presentato il seguente errore:

Cannot resolve the collation conflict between "Latin1_General_CI_AS" and "SQL_Latin1_General_CP1_CI_AS" in the equal to operation

Il collate è la clausola che è possibile applicare a una definizione di database o di colonna per definire le regole di confronto oppure a un'espressione stringa di caratteri per applicare il casting delle regole di confronto.

Ovviamente se DB differenti hanno collate differenti non può confrontare i campi (ma ci sono gli stessi problemi con un select/insert tra database)

Una soluzione è forzare un collate nella query:

SELECT search.* FROM categories 
INNER JOIN search ON categories.cid = search.cat_id collate SQL_Latin1_General_CP1_CI_AS

Ma ovviamente se il problema è in tutta l’applicazione questa modifica potrebbe essere eccessivamente invasiva Confused smile

Cambiare il collate nelle opzioni del database non è la soluzione, poiché le colonne già create si tengono il loro collate…

Ma qui ho trovato la soluzione… una query da lanciare per avere gli script di migrazione belli pronti:

DECLARE @collate SYSNAME
SELECT @collate = 'Cyrillic_General_CS_AS'

SELECT
'[' + SCHEMA_NAME(o.[schema_id]) + '].[' + o.name + '] -> ' + c.name
, 'ALTER TABLE [' + SCHEMA_NAME(o.[schema_id]) + '].[' + o.name + ']
ALTER COLUMN ['
+ c.name + '] ' +
UPPER(t.name) +
CASE WHEN t.name NOT IN ('ntext', 'text')
THEN '(' +
CASE
WHEN t.name IN ('nchar', 'nvarchar') AND c.max_length != -1
THEN CAST(c.max_length / 2 AS VARCHAR(10))
WHEN t.name IN ('nchar', 'nvarchar') AND c.max_length = -1
THEN 'MAX'
ELSE CAST(c.max_length AS VARCHAR(10))
END + ')'
ELSE ''
END + ' COLLATE ' + @collate +
CASE WHEN c.is_nullable = 1
THEN ' NULL'
ELSE ' NOT NULL'
END
FROM sys.columns c WITH(NOLOCK)
JOIN sys.objects o WITH(NOLOCK) ON c.[object_id] = o.[object_id]
JOIN sys.types t WITH(NOLOCK) ON c.system_type_id = t.system_type_id AND c.user_type_id = t.user_type_id
WHERE t.name IN ('char', 'varchar', 'text', 'nvarchar', 'ntext', 'nchar')
AND c.collation_name != @collate
AND o.[type] = 'U'

Happy Sql-ing Winking smile
Technorati Tags: ,

Radical => WPF Drag&Drop to the max

Per un programma che sto sviluppando in questi giorni mi sono trovato a dover gestire il drag&drop tra controlli WPF.

Ho deciso di utilizzare il Framework Radical di Mauro Servienti per implementare il pattern MVVM nella mia applicazione desktop.

Il programma è una sorta di designer che posiziona elementi (raffigurati da rettangoli) su una superficie piana. Gli elementi possono essere posizionati o attraverso il drag&drop, o attraverso un doppio click sull’elemento stesso.

Nel codice sorgente che trovate allegato vi ho creato la stessa situazione, in una versione semplificata, utile a capire come Radical permette di gestire la cosa con poche righe di codice.

Iniziamo installando l’estensione Radical Templates che aggiungerà i Radical Project Templates a Visual Studio. In questo modo sotto i templates per i progetti Windows Desktop troveremo una sottocartella con i template per Radical che creeranno per noi una nuova soluzione già funzionante che implementa questo framework. L'estensione per Visual Studio non è un requisito ma una semplice comodità per essere operativi in meno tempo.

Il framework utilizza le convenzioni per facilitarci l’utilizzo del pattern MVVM, quasi senza accorgerci di utilizzarlo.

Non è questo il post dove sviscerare tutte le feature, di cui vi è ampia documentazione, di questo framework, ma guardando il sorgente noterete come risulta veramente facile ed espressivo, senza avere un mucchio di codice per la comunicazione tra View e ViewModel, che in soluzioni non banali genera solo molto “rumore”.

Passiamo alla gestione del Drag&Drop:

dopo aver aggiunto il riferimento ai behaviors:

xmlns:behaviors="http://schemas.topics.it/wpf/radical/windows/behaviors"

basterà aggiungere le Attached Properties “behaviors:DragDropManager.DataObject” e “behaviors:DragDropManager.DataObjectType” al controllo da cui partiamo con il drag, mentre dovremo aggiungere la gestione del DropCommand sul controllo che subirà il drop con questa semplice riga di codice:

behaviors:DragDropManager.OnDropCommand="{markup:AutoCommandBinding Path=DropItem}"

Grazie a Radical, “DropItem” è seplicemente una funzione void del ViewModel che si preoccupa di gestire il drop dell’elemento.

Poiché volevo rendere evidente dove sarebbe stato depositato l’elemento, ho aggiunto la gestione di altri due eventi:

behaviors:DragDropManager.OnDragEnterCommand="{markup:AutoCommandBinding Path=DragEnter}"  
behaviors:DragDropManager.OnDragLeaveCommand="{markup:AutoCommandBinding Path=DragLeave}"

Che permettono di gestire l’ingresso e uscita dal controllo, rendendo evidente, con un altro colore, dove sarà depositato l’elemento.

Ah… mi sono dimenticato… per la gestione del doppio click basta un’altra riga di codice:

behavior:ListViewManager.ItemDoubleClickCommand="{markup:AutoCommandBinding Path=ListViewDoubleClick}"

Insomma, se guardate il codice c’è più codice nello XAML dei controlli che per l’implementazione di MVVM con Radical, ma volevo farvi assaggiare le potenzialità di questo framework in un'applicazione per lo meno “non banale”.

Il sorgente di esempio lo trovate al seguente indirizzo: http://1drv.ms/1Ar8dD6

Spero di aver stuzzicato la vostra curiosità e, se vi ho incuriositi, volentieri posterò altro su Radical. Winking smile

P.S. un grazie speciale a Mauro per il supporto! Smile

Technorati Tags: ,,

L’importanza del contesto

Penso di non essere il solo ormai così abituato ad usare Entity Framework e LINQ da dimenticarmi i principi fondamentali tra su cui si basa Entity Framework finché non ci sbatto il muso…. Come oggi Smile

Sto sviluppando la classica applicazioni di scambio dati tra sistemi legacy che fa un uso (ovviamente) importate dell’accessoacesso ai dati. Per cui cosa c’è di più comodo che un bel “reverse engineering” del database legacy per poi poterci operare con LINQ?Smile with tongue out

Tutto filava per il meglio con mia grande soddisfazione finché non si è presentato il caso di dover chiamare un applicativo esterno che era preposto a fare delle modifiche allo stesso database ma la cui logica era cablata nell’eseguibile e quindi “doveva essere usata così com’era”.

Vi riporto la parte di codice “incriminata”. Il programma reale è (ovviamente) un po’ più complesso e la logica è distribuita su più funzioni (altrimenti il problema mi sarebbe saltato subito all’occhio) ma rende l’idea del “pitfall” in cui si può cadere usando Entity Framework (o un qualsiasi altro ORM) come usiamo (o usavamo) ADO.NET.

N.d.R. “ShellandWait” è una funzione che si preoccupa di lanciare un programma con un parametro ed attenderne la chiusura e…. scusate la sintassi VB Embarrassed smile

Using ctx = provider.GetDataContext() Dim ordini = From p In ctx.PortafoglioOrdini Where p.Ordine = ordine Select p If ordini IsNot Nothing Then For Each ordine In ordini Dim res = ShellandWait(programmaEsterno, ordine.Riga) Next End If Dim ordineModificato = (From p In ctx.PortafoglioOrdini Where p.Ordine = ordine Select p).FirstOrDefault() Return (ordineModificato IsNot Nothing AndAlso ordineModificato.Stato = "X") End Using

 

Diciamo (sempre per semplificare) che tra le varie cose che fa il programma esterno una di quelle è cambiare una colonna della tabella PortafoglioOrdini e io uso questa modifica per verificare che il programma abbia girato correttamente.

Ma il controllo mi tornava sempre false, benché la verifica sul database rendesse evidente che tutto funzionasse al meglio. Surprised smile

Quello che mi ero dimenticato è che il DbContext di Entity Framework implementa i pattern della Unit Of Work e Identity Map per cui una volta letti i dati non li rilegge più dal DB poiché, correttamente in quasi tutti i casi, ritiene di avere conoscenza dello stato letto e di tutte le modifiche apportate al dato che siano state persistite o meno.

Capito il problema (e per una volta senza ricorrere a Stack Overflow Winking smile ) ho risolto facilmente il problema dividendo il singolo DbContext in due differenti, uno prima e uno dopo la chiamata al programma esterno.

Technorati Tags: ,

Se il dev non va a CQRS...

Premessa: mi rendo conto che questo potrà apparire come un “piccolo spazio pubblicità”, ma in realtà è solo dettato da quell’entusiasmo che mi guida e sprona in questo bellissimo lavoro che ci accomuna. Chiarito questo… Winking smile

Poco più di un annetto fa mi sono imbattuto in Command Query Resposability Segregation (CQRS) e Event Sourcing (ES). Non vi sto a dire che cosa sono perché se usate un qualsiasi motore di ricerca potete trovare migliaia di articoli in qualsiasi lingua che lo spiegano meglio di quanto potrei farlo io.

Devo ammettere che al primo impatto ho capito veramente poco e mi sono detto: “sarà la solita moda del momento che passerà in fretta”, ma qualche spunto e qualche post letto poi a casa mi avevano lasciato una certa curiosità di approfondire l’argomento. Per cui ho girato un po’ di conferenze in giro per l’Italia e alla fine ho capito le potenzialità dei due strumenti. Ve la faccio breve: se come me avevate visto le potenzialità di DDD ma avevate problemi a capire come calarle nelle vostre soluzioni, questi due strumenti possono essere una valida soluzione.

Non vi nascondo che essendo delle soluzioni architetturali “giovani” la loro implementazione non è proprio una passeggiata e per evitare di fare danni maggiori ai benefici e partire con il piede giusto  è necessario comprendere la filosofia che ci sta dietro. Ma le potenzialità sono enormi, specialmente se come capita a quasi a tutti (me compreso) una applicazione (o un insieme di applicazioni) continuano a crescere per anni rendendo complessa la loro gestione/manutenzione/crescita.

Se tutto questo vi suona famigliare, CQRS può essere una soluzione e ora non avete più scuse perché CQRS viene da voi… a breve, infatti, partirà un tour che coprirà gran parte dell’Italia proprio su CQRS e su an altro argomento caldo del momento: AngularJs e le applicazioni SPA.

Le tappe saranno Padova, Torino, Napoli e Bari, organizzate da Ynnova in collaborazione con Mauro Servienti di Managed Designs.

Per le informazioni dettagliate le trovate qui.

Ora non avete più scuse! ;)

Technorati Tags: ,

App Challenge XMAS 3 - WP8+W8

Siete bravi sviluppatori Window Phone 8 e Windows 8? Questa challenge di Nokia DVLUP fa decisamente per voi!

Se sviluppate due nuove app per Windows Phone e due per Windows 8 guadagnate 800 XP che vi serviranno per i ricchi premi messi a disposizione da questo rewards program.

Ma non è finita qui: se ci mettete vicino un’altra app per ciascuna piattaforma (passando quindi a tre app per piattaforma) avrete in regalo un Lumia 925. Sorpresa

Sicuramente non è facile, visto il poco tempo a vostra disposizione, ma in questo caso lo sforzo vale sicuramente la candela!

E ricordatevi che avete a disposizione anche l’App Studio per aiutarvi in quest’ardua impresa.

Vi chiedo solo di impegnarvi a fare delle app di qualità e non solo orientate ad ottenere il premio… un po’ di #OrgoglioDev!!!! Occhiolino

In bocca al lupo!

Tag di Technorati: ,,,

Entity Framework e gli errori di validazione

Se usate Entity Framework e se, come me, allineate le piccole modifiche sul “dominio” con modifiche manuali sul DB (specialmente quando avete anni di dati dentro Winking smile), vi può capitare di ottenere il seguente errore:

Validation failed for one or more entities. See 'EntityValidationErrors' property for more details

 

A volte scoprire dov’è il problema di validazione non è così facile e può venire utile metterci un try-catch di questo tipo:

try
{
    ctx.SaveChanges();
}
catch (DbEntityValidationException e)
{
    foreach (var eve in e.EntityValidationErrors)
    {
        Debug.Print("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
            eve.Entry.Entity.GetType().Name, eve.Entry.State);
        foreach (var ve in eve.ValidationErrors)
        {
            Debug.Print("- Property: \"{0}\", Error: \"{1}\"",
                ve.PropertyName, ve.ErrorMessage);
        }
    }
    throw;
}

Ovviamente grazie a Stackoverflow per la dritta Smile

Certo, se usaste CQRS e I database documentali non avreste di questi problemi, ma questa è un’altra storia Winking smile

Update e Inner Join in SQL

Si… lo so… ormai il mondo dello sviluppo si muove su altre strade (ORM, CQRS, DB documentali), ma a volte abbiamo a che fare con il buon vecchio SQL.

Ogni volta che aggiungo una anagrafica dove prima c’era il “codice secco” non mi ricordo come aggironare in una sola volta tutti gli id della tabella…

…beh ecco un memo se siete come me Winking smile

UPDATE b 
SET    b.article_id = a.id 
FROM   billofmaterials b 
       INNER JOIN articles a 
               ON b.articlecode = a.code 
WHERE  b.article_id IS NULL 
Technorati Tags: ,,

I <3 LINQ

Ho ripreso in mano un progetto scritto sei anni fa. Devo dire che LINQ e gli Extension Methods sono dei gran strumenti.

        internal Dictionary<string, int> GetDictionaryCountries()
        {
            var retDict = new Dictionary<string, int>();
            using (ISession session = SessionHelper.GetSession())
            {
                IList<object> objList = session.CreateQuery("select i.Code, i.Id from Country i").List<object>();
                foreach (object obj in objList)
                {
                    Array arr = (Array)obj;
                    retDict.Add(Convert.ToString(arr.GetValue(0)), Convert.ToInt32(arr.GetValue(1)));
                }
            }
            return retDict;
        }

Diventa:

        internal Dictionary<string, int> GetDictionaryCountries()
        {
            using (ISession session = SessionHelper.GetSession())
            {
                return session.Query<Country>().Select(x => new { x.Code, x.Id }).ToDictionary(x => x.Code, x => x.Id);
            }
        }
Devo aggiungere altro? Open-mouthed smile

 

P.S. la versione 1 era pure in VB.NET ma l’ho tradotta per un confronto più facile Winking smile

P.P.S. Non sparate sul pianista sul perchè faccio una cosa del genere o quanto fa schifo tornare un dictionary, è stato il primo programma scritto in .NET Embarrassed smile

Technorati Tags: ,

Radical – A new day has come <cit.>

Questo è il primo di alcuni articoli che tratteranno l’utilizzo del framework Radical, sviluppato da Mauro Servienti.

Qualche premessa:

  1. molto di quello che trovate qui lo potete trovare anche sulla documentazione di Radical che Mauro sta scrivendo, in inglese, impegni lavorativi permettendo;
  2. lo scopo di questi post è presentarvi alcune facilities che questo framework mette a disposizione, in italiano! Occhiolino;
  3. io ho sempre trovato poco intuitivo l’utilizzo del toolkit MVVM Light Toolkit;
  4. non mi piace molto l’utilizzo che fa Caliburn.Micro della proprietà Name dei controlli per il binding (mi hanno sempre detto: “in MVVM usare Name è MALE!” A bocca aperta), ma ammetto che è questione di gusti;
  5. trovavo noioso e “error-prone” dover scrivere centinaia di righe di codice solo per gestire in maniera “decente” l’iterazione con l’utente.

Da queste poche righe, capite che fino a poco tempo fa il mio rapporto con MVVM e il databinding era molto problematico e  alla fine ricadevo sempre sulle care e vecchie Windows Forms che almeno mi consentivano un miglior controllo sull’iterazione con la UI.

In tutti i progetti di esempio, infatti, vengono dimostrati i vantaggi del data binding facendo vedere come, con due righe di codice, puoi recuperare i dati e visualizzarli, ma non fanno vedere che, una volta applicato il pattern MVVM, ci si scontra con molti altri problemi che non avevamo con le vecchie WinForms, ad esempio: la gestione delle finestre di dialogo dal ViewModel, il passaggio di parametri tra View (o ViewModel), fino ad arrivare al problema di dover gestire il data binding con controlli che non lo prevedono (PasswordBox) Perplesso

Radical ha una risposta a tutti questi problemi ed a molti altri e vi semplificherà la vita e diminuendo del 50% il codice che state scrivendo se usate MVVM Light Toolkit (esperienza diretta su un mio progetto).

Partiamo da una guida in 8 passi per creare un progetto funzionate (in C#):

  1. Create una nuova applicazione WPF;
  2. Aggiungete, attraverso Nuget, un riferimento a  Radical.Windows.Presentation.CastleWindsor (ma se preferite o il vostro progetto usa già un altro IoC container sono supportati anche Unity2, Unity3, Autofac e Puzzle per le app RT). Nota: se non trovate il riferimento giusto dovete solo selezionare “Include Prelerase” nella ricerca dei pacchetti Nuget;
  3. Cancellate la Window creata di default da Visual Studio (MainWindow.xaml);
  4. Modificate il file "app.xaml" rimuovendo l'attributo "StartupUri"
  5. Aggiungete un folder “Presentation” al progetto (è il folder dove Radical cerca di default le View e i ViewModel);
  6. Create una nuova window chiamandola “MainView.xaml” (di default Radical considera Views le windows il cui nome finisce per “View”);
  7. Create una nuova classe chiamandola “MainViewModel.cs” (di default Radical considera ViewModels le classi il cui nome finisce per “ViewModel” e le lega alla View che ha la stessa radice);

Andate nel file “app.xaml.cs” e aggiungete una singola riga di codice (ovviamente cambiando la dichiarazione del bootstrapper a seconda dell’IoC container scelto):

    public partial class App : Application
    {
        public App()
        {
            var bootstrapper = new WindsorApplicationBootstrapper<MainView>();
        }
    }

Premete F5 e tutto funzionerà, ossia si apre una Window vuota! A bocca aperta

Come avrete capito anche Radical si basa sul paradigma Convention Over Configuration e dietro le quinte ha:

  1. Legato la View e il ViewModel senza dover aggiungere alcunché;
  2. Fatto partire la View da noi scelta (in questo caso la “MainView”);
  3. Reso la MainView singleton (per convenzione se la View inizia per “Main” o “Shell” allora è singleton);
  4. Abilitato molte altre cose che in progetto vuoto come questo non è possibile farvi vedere Occhiolino
  5. Ovviamente tutte queste convenzioni possono essere “overridate” all’occorrenza Caldo

Ora abbiamo una Window vuota che dalla prossima volta vedremo di riempire con qualche controllo e un po’ di logica in modo da esplorare le altre potenzialità di questo framework.

Tag di Technorati: ,
«novembre»
domlunmarmergiovensab
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567