jeudi 28 juin 2012

ADO.NET - Entity Framework

Entity Framework 4.1 ou plus introduit une nouvelle API basée sur la classe DbContext qui propose trois approches :

  • "Model First" : le modèle des données est créé via le concepteur Visual Studio
  • "Database First" : le modèle des données est créé à partir d'une base de données existante, modifié dans Visual Studio. Un modèle T4 permet de générer le code des entités correspondantes (par défaut avec l'ancienne API ObjectContext ou sur demande avec la nouvelle API DbContext).
  • "Code First" : le modèle des données est défini directement dans le code de l'application.
Le fichier utilisé sera cette fois C:\Program Files\Microsoft SQL Server Compact Edition\v4.0\Samples, la version 3.5 ne permettant pas de récupérer les valeurs "identity". De même le fichier de configuration de l'application est changé pour adresser cette version :
<configuration>
  <connectionStrings>
    <add name="Data" connectionString="Data Source=Northwind.sdf" providerName="System.Data.SqlServerCe.4.0"/>
  </connectionStrings>
</configuration>
Le fichier Category.cs va permettre de décrire la classe qui va représenter nos données :
namespace ConsoleApplication1
{
    public class Category
    {
        public virtual int CategoryID { get; set; }
        public virtual string CategoryName { get; set; }
    }
}
Le fichier Data.cs décrit le "contexte" qui permettra de prendre en charge la mise à jour de la base :
using System.Data.Entity;
namespace ConsoleApplication1
{
    public class Data : DbContext
    {
        public DbSet Categories { get; set; }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity().Property(p => p.CategoryID).HasColumnName("Category ID");
            modelBuilder.Entity().Property(p => p.CategoryName).HasColumnName("Category Name");
        }
    }
}
La méthode OnModelCreating permet notamment d'indiquer les noms des colonnes présentes dans la base de données. Par convention, la table porte le même nom que la classe et une propriété dont le nom se termine par "id" est une clé primaire. Au final, le code permet d'accéder très naturellement à la liste des catégories :
using System;
using System.Linq;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Data data = new Data();
            foreach (var item in from o in data.Categories orderby o.CategoryName ascending select o)
            {
                item.CategoryName = item.CategoryName.EndsWith("z") ? item.CategoryName.Substring(0,item.CategoryName.Length - 1) : item.CategoryName + "z";
                Console.WriteLine(item.CategoryName);
            }
            data.SaveChanges();
            Console.ReadKey();
        }
    }
}
La ligne foreach peut également être exprimée sous la forme foreach(var item in data.Categories.OrderBy((o)=>o.CategoryName)).

mercredi 27 juin 2012

ADO.NET - Mode déconnecté

La classe Data reste globalement inchangée et n'ajoute qu'une méthode GetAdapter. L'objet retourné par cette méthode répertorie les différentes commandes qui vont permettre de supprimer, créer, mettre à jour les données, commandes générés à partir de la requête de sélection :

        public DbDataAdapter GetAdapter(string commandText,params object[] values)
        {
            var builder = factory.CreateCommandBuilder();
            builder.DataAdapter = factory.CreateDataAdapter();
            builder.DataAdapter.SelectCommand = GetCommand(commandText, values);
            builder.DataAdapter.DeleteCommand = builder.GetDeleteCommand();
            builder.DataAdapter.InsertCommand = builder.GetInsertCommand();
            builder.DataAdapter.UpdateCommand = builder.GetUpdateCommand();
            builder.DataAdapter.SelectCommand.Connection.Close();
            return builder.DataAdapter;
        }
Cet objet peut alors être utilisé dans le programme principal pour lire les données dans un objet DataTable ou DataSet (qui représentent un cache en lecture/écriture d'une table ou d'un ensemble de tables). Les données stockées par cet objet peuvent alors être modifiées à volonté avant d'appeler la méthode Update qui va examiner l'état des différentes lignes (modifiée, supprimée, insérée) pour envoyer les modifications correspondantes vers la base de données :
using System;
using System.Data;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var Data= new App.Data();
            var adapter=Data.GetAdapter("SELECT [Category ID],[Category Name] FROM Categories ORDER BY [Category Name]");
            var table = new DataTable();
            adapter.Fill(table);
            // Déconnecté
            foreach(DataRow row in table.Rows)
            {
                var value = (string)row["Category Name"];
                value=value.EndsWith("z")?value.Substring(0,value.Length-1):value+"z";
                row["Category Name"] = value;
                Console.WriteLine(value);
            }
            // Exécuter toutes les mises à jour
            adapter.Update(table);
            Console.ReadKey();
        }
    }
}>
Dans le mode déconnecté comme connecté, on note l'utilisation d'objets spécifiques au transfert de données entre la base et l'application, qu'il s'agisse d'un "Reader", "DataTable" ou "DataSet". Même si les "DataSet typés" permettent d'exposer ces données d'une façon plus fortement typée, cela reste une solution hybride.

L'évolution ultime de ADO.NET, Entity Framework, a pour but de résoudre cette friction en exposant les données de la base sous forme d'objets .NET tout à fait ordinaires et c'est ce que nous allons voir maintenant.

mardi 26 juin 2012

ADO.NET - Mode connecté

Une application "Console" va illustrer les principes de base d'une application ADO.NET en mode connecté. Dans cette solution nous allons d'abord ajouter le fichier C:\Program Files\Microsoft SQL Server Compact Edition\v3.5\Samples\Northwind.sdf. SQL Server Compact est une base de données orientée fichier, installable facilement sous forme d'une DLL et idéale pour les applications de bureau qui nécessitent une base de données locale. Le fichier App.config ajouté également à la solution, va alors indiquer les informations de connection à ce fichier base de données :

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <connectionStrings>
    <add name="Data" connectionString="Data Source=Northwind.sdf" providerName="System.Data.SqlServerCe.3.5"/>
  </connectionStrings>
</configuration>
Bien que la plupart des exemples simples ne montrent pas cette approche, pour faciliter le plus possible une adaptation à d'autres bases de données, la connection sera créée en utilisant une "fabrique" qui va permettre de créer une connection dont le type dépend de la valeur de l'attribut providerName présente dans le fichier de configuration ci-dessus. On retrouvera donc dans le code suivant :
  • Le constructeur Data initialise un accès au fichier de configuration et la fabrique correspondant à ce fournisseur.
  • La méthode GetConnection initialise la connection à la base de données.
  • La méthode GetCommand s'appuie sur cette méthode pour initialiser une commande SQL paramétrée.
  • La méthode ExecuteReader s'appuie sur la méthode précédente pour initialiser le "lecteur" qui permettra de lire les données en provenance de la base
ce qui donne donc au final le code suivant :
using System;
using System.Configuration;
using System.Data.Common;
namespace ConsoleApplication1.App
{
    class Data
    {
        private const string ConnectionStringName="Data";
        private ConnectionStringSettings connectionSettings;
        private DbProviderFactory factory;
        public Data()
        {
            // Lecture du fichier de configuration
            connectionSettings=System.Configuration.ConfigurationManager.ConnectionStrings[ConnectionStringName];
            // "Fabrique" pour le fournisseur indiqué
            factory = DbProviderFactories.GetFactory(connectionSettings.ProviderName);
        }
        private DbConnection GetConnection()
        {
            // Créer et ouvrir une connexion
            DbConnection cnn = factory.CreateConnection();
            cnn.ConnectionString = connectionSettings.ConnectionString;
            cnn.Open();
            return cnn;
        }
        public DbCommand GetCommand(string commandText,params object[] values)
        {
            // Créer une commande paramétrée
            DbConnection cnn = GetConnection();
            DbCommand cmd = cnn.CreateCommand();
            cmd.CommandText = commandText;
            for (int i = 0; i < values.Length; i++)
            {
                DbParameter prm = cmd.CreateParameter();
                prm.ParameterName = i.ToString();
                prm.Value = values[i];
                cmd.Parameters.Add(prm);
            }
            return cmd;
        }
        public DbDataReader ExecuteReader(string commandText,params object[] values)
        {
            // Créer un "lecteur"
            DbCommand cmd = GetCommand(commandText,values);
            DbDataReader dataReader = cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection);
            return dataReader;
        }
    }
}
Cette classe peut alors être utilisée par le code principal qui modifie le libellé en ajoutant ou supprimant une lettre "z" finale :
using System;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var Data= new App.Data();
            var cmd = Data.GetCommand("UPDATE Categories SET [Category Name]=@0 WHERE [Category ID]=@1", "", 0);
            var rdr = Data.ExecuteReader("SELECT [Category ID],[Category Name] FROM Categories ORDER BY [Category Name]");
            while (rdr.Read())
            {
                var value=rdr.GetString(1);
                value=value.EndsWith("z")?value.Substring(0,value.Length-1):value+"z";
                cmd.Parameters[0].Value = value;
                cmd.Parameters[1].Value = rdr.GetInt32(0);
                Console.WriteLine(rdr.GetString(1)+", "+cmd.ExecuteNonQuery()+", "+value);
            }
            rdr.Close();
            cmd.Dispose();
            Console.ReadKey();
        }
    }
}
Cet exemple permet de voir rapidement les bases de l'utilisation du mode connecté qui permet de "consommer" immédiatement les données en provenance de la base. Nous allons voir maintenant rapidement le mode déconnecté.

Windows 8

Ce mois ci a vu plusieurs annonces importantes :

  • 1er juin 2012 : "Windows 8 Release Preview" est disponible...
  • 18 juin 2012 : Microsoft commercialisera ses propres tablettes Windows 8 "Surface".
  • 21-22 juin 2012 : Windows Phone Summit
    • Windows Phone 8 ne tournera malheureusement pas sur le matériel Windows Phone 7.x. Windows Phone 7.8 apportera le nouvel écran de démarrage de Windows Phone 8.
    • Shared Windows Core : Windows Phone 8 partage une partie de son code avec Windows.
    • Les applications Windows Phone 7 fonctionnent malgré un changement de résolution.
    • Support des cartes SD.
    • Internet Explorer 10.
    • Plateforme commune DirectX en code natif pour Windows 8 et Windows Phone 8
    • Transfert sans contact (NFC - Near Field Communication)
    • Porte-monnaie électronique notamment avec Orange
    • Cartographie Nokia
    • Fonctionalités d'administration pour les entreprises (dont notamment le déploiement d'applications métier)
    • Nouvel écran de démarrage

vendredi 1 juin 2012

Bienvenue

Introduction

Des informations détaillées sur les différentes technologies proposées par Microsoft, sont déjà largement disponibles sur le web, soit via l'incontournable site "Microsoft Developper Network" (MSDN), soit via de nombreux sites ou blogs communautaires. Par contre, la palette des technologies de développement s'élargie sans cesse et il reste sans doute assez difficile pour un développeur, de suivre les progrès des différentes technologiques disponibles, ou à fortiori pour un débutant, d'acquérir rapidement une vue d'ensemble de ces mêmes technologies. Dans ce blog, je vais donc plutôt essayer d'aborder progressivement, de façon structurée, les différentes étapes de réalisation d'une application et donner un panorama des solutions techniques disponibles pour traiter chacune de ces étapes.

Plan du site

  • Bonnes pratiques
  • Accès aux données
    • ADO.NET
    • Entity Framework
  • Technologies du web
    • HTML
    • CSS
    • JavaScript
    • HTTP
    • ASP.NET
      • Dynamic Data
      • MVC
      • Web Forms
      • Silverlight (XAML)
  • Clients Windows
    • Windows Forms
    • Windows Presentation Foundation (XAML)
    • Metro (XAML)