Calendrier

Décembre 2009
L M M J V S D
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      
<< < > >>

Présentation

Recherche

W3C

  • Flux RSS des articles

Code Fluent

[Code Fluent] –
Redéfinir la chaine de connexion
Ajouter une méthode manuellement
a- Redéfinir la chaine de connexion
Il est possible de redéfinir la chaine de connexion si vraiment on le désire ..
            // récupèration
            CodeFluent.Runtime.CodeFluentPersistence persistence = CodeFluentContext.Get(CFContacts.Constants.CFContactsStoreName).Persistence;
            // OU création d'un objet persistence
            CodeFluent.Runtime.CodeFluentPersistence persistence = CodeFluentContext.GetNew("CFContact").Persistence;
            // >> redéfinition de la chaine de connexion
            persistence.ConnectionString = @"Data Source=.;Initial Catalog=CFContacts;Integrated Security=SSPI";
           
 
b-Ajouter une méthode    “ à la main”
Exemple j’ajoute une méthode à ContactCollection qui retournera une collection de contacts
public static ContactCollection FindAllContactsStartsWith(string start)
        {
            ContactCollection result = new ContactCollection();
 
            //Connexion
            CodeFluent.Runtime.CodeFluentPersistence persistence = CodeFluentContext.Get(CFContacts.Constants.CFContactsStoreName).Persistence;
          
            // on crée une command appelant la procédure stockée persistence.CreateStoredProcedureCommand("Contact_FindAllStartsWith");
            persistence.AddParameter("@Start", start);
 
            System.Data.IDataReader reader = CodeFluentContext.Get(CFContacts.Constants.CFContactsStoreName).Persistence.ExecuteReader();
            while (reader.Read())
            {
                CFContacts.Contact contact = new CFContacts.Contact();
                ((CodeFluent.Runtime.ICodeFluentEntity)(contact)).ReadRecord(reader);
                result.Add(contact);
            }
 
           reader.Close();
           reader.Dispose();
            return result;
        }
Par Romagny13
Ecrire un commentaire - Voir les 1 commentaires - Recommander
[ Code Fluent ]
Requêter en . NET 3.0
avec Linq To Objects  
 

j’ai parlé un peu vite on peut quand même bien sur requêter avec  Linq To Objects sur les classes collections générées avec Code Fluent (il suffit de caster)
le but étant de pouvoir trier et filtrer sur la couche métier
           ContactCollection Contacts = ContactCollection.LoadAll();
 
            var Query =
                from c in Contacts.Cast<Contact>()
                where c.ContactName.StartsWith("R")
                orderby c.ContactName
                select c;
 
 
            dataGridView1.DataSource = Query.ToList<Contact>();
           
 
Se créer des methodes recevant  un délégué afin de simuler les predicates des generics de .NET 2.0
-          Avec une méthode FindAll (possible en .NET 1.0) dans la classe Collection (ici ContactCollection)
        public delegate bool Predicate(Contact obj);
 
        public ContactCollection FindAll(Predicate predicate)
        {
            ContactCollection result = new ContactCollection();
            foreach (Contact oContact in this)
            {
                if (predicate(oContact))
                    result.Add(oContact);
            }
            return result;
        }
 
 
Utilisation :
private void button1_Click(object sender, EventArgs e)
        {
            ContactCollection Contacts = ContactCollection.LoadAll();
            ContactCollection result = Contacts.FindAll(new stringPredicate(stringCondition.StartsWith, "ContactName", "R").Predicate);
            dataGridView1.DataSource = result;
           
        }
 
-          Avec les extensions methods (à partir de .NET 3.0)
 public static class extensionMethods
    {
        public static ContactCollection FindAll(this ContactCollection source, System.Predicate<Contact> predicate)
        {
            ContactCollection result = new ContactCollection();
            foreach (Contact oContact in source)
            {
                if (predicate(oContact))
                    result.Add(oContact);
            }
            return result;
        }
    }
 
Note :
La classe que j’utilise ici
public class stringPredicate
    {
        private stringCondition _Condition;
 
        ///<summary>
        ///
        ///</summary>
        public stringCondition Condition
        {
            get { return _Condition; }
            set { _Condition = value; }
        }
        private string _Property;
 
        ///<summary>
        ///
        ///</summary>
        public string Property
        {
            get { return _Property; }
            set { _Property = value; }
        }
        private string _Value;
 
        ///<summary>
        ///
        ///</summary>
        public string Value
        {
            get { return _Value; }
            set { _Value = value; }
        }
 
        ///<summary>
        ///
        ///</summary>
        public stringPredicate()
        { }
 
        ///<summary>
        ///
        ///</summary>
        ///<param name="Condition"></param>
        ///<param name="Property"></param>
        ///<param name="Value"></param>
        public stringPredicate(stringCondition Condition, string Property, string Value)
        {
            this.Condition = Condition;
            this.Property = Property;
            this.Value = Value;
        }
 
        ///<summary>
        ///
        ///</summary>
        ///<param name="Condition"></param>
        ///<param name="Property"></param>
        ///<param name="Value"></param>
        public void SetProperties(stringCondition Condition, string Property, string Value)
        {
            this.Condition = Condition;
            this.Property = Property;
            this.Value = Value;
        }
 
        ///<summary>
        ///
        ///</summary>
        ///<param name="obj"></param>
        ///<returns></returns>
        public bool Predicate(object obj)
        {
            bool result = false;
            string CurrentPropertyValue = Convert.ToString(PredicateUtils.GetValue(obj, Property));
 
            switch (Condition)
            {
                case stringCondition.Contains:
                    result = CurrentPropertyValue.Contains(Value);
                    break;
                case stringCondition.EndWith:
                    result = CurrentPropertyValue.ToLower().EndsWith(Value.ToLower());
                    break;
                case stringCondition.EndWithMatchCase:
                    result = CurrentPropertyValue.EndsWith(Value);
                    break;
                case stringCondition.Equals:
                    result = CurrentPropertyValue.Equals(Value);
                    break;
                case stringCondition.Length:
                    if (CurrentPropertyValue.Length > Convert.ToInt32(Value))
                        result = true;
                   else
                        result = false;
                    break;
                case stringCondition.StartsWith:
                    result = CurrentPropertyValue.ToLower().StartsWith(Value.ToLower());
                    break;
                case stringCondition.StartsWithMatchCase:
                    result = CurrentPropertyValue.StartsWith(Value);
                    break;
                case stringCondition.IsMatch:
                    Regex oRegex = new Regex(Value);
                    result = oRegex.IsMatch(CurrentPropertyValue);
                    break;
            }
 
            return result;
        }
    }
    public class PredicateUtils
    {
        public static object GetValue(object obj, string Property)
        {
            return obj.GetType().GetProperty(Property).GetValue(obj, null);
        }
    }
    public enum stringCondition
    {
        Contains,
        EndWith,
        EndWithMatchCase,
        Equals,
        Length,
        StartsWith,
        StartsWithMatchCase,
        IsMatch
    }
 
 
Par Romagny13
Ecrire un commentaire - Voir les commentaires - Recommander
CodeFluent – Procédures stockées

CodeFluent repose énormément pour ne pas dire uniquement sur les procédures stockées
Il est possible de définir dans les fichiers Xml de définition des entités ses propres procédures stockées …
Je crée 2 procédures (celles –ci sont placées dans le « corps » de l’entité concernée, ici Contact):
-          FindFirstStartsWith retournera 1 objet contact(>loadone)
-          FindAllStartsWith retournera une collection de contacts (>load)
On peut définir les contraintes des paramètres avec la balise <cf :parameter/>
<cf:project xmlns:cf="http://www.softfluent.com/codefluent/2005/1"
                  xmlns:cfpc="http://www.softfluent.com/codefluent/producers.cache/2005/1"
                  defaultNamespace="CFContacts"
                  persistencePropertyNameFormat="{1}"
                  defaultKeyPropertyTypeName="int">
 <!-- inclut le fichier CFContactsProducerAll.xml -->
 <cf:importpath="CFContactsProducerAll.xml" />
 <!-- definition de 2 entités -->
 <Contact>
    <Id/>
    <ContactName/>
    <ContactFirstName/>
    <ContactAge typeName="int"/>
    <ContactBirth typeName="datetime"/>
    <ContactCategory typeName="ContactCategory"/>
    <cf:method name="FindFirstStartsWith" body="loadone where ContactName Like @start" >
      <cf:parameter name="Start" nullable="false" />
    </cf:method>
    <cf:method name="FindAllStartsWith" body="load where ContactName Like @Start" >
      <cf:parameter name="Start" nullable="false" />
    </cf:method>
 </Contact>
 <ContactCategory>
    <Id/>
    <ContactCategoryLabel/>
 </ContactCategory>
</cf:project>
 
Les 2 procédures stockées correspondantes générées
CREATE PROCEDURE [dbo].[Contact_FindAllStartsWith]
(
 @Start [nvarchar] (256),
 @_orderBy0 [nvarchar] (64) = NULL,
 @_orderByDirection0 [bit] = 0
)
AS
SET NOCOUNT ON
SELECT DISTINCT [Contact].[Id], [Contact].[ContactName], [Contact].[ContactFirstName], [Contact].[ContactAge], [Contact].[ContactBirth], [Contact].[ContactCategory_Id], [Contact].[_trackLastWriteTime], [Contact].[_trackCreationTime], [Contact].[_trackLastWriteUser], [Contact].[_trackCreationUser], [Contact].[_rowVersion]
    FROM [Contact]
    WHERE ([Contact].[ContactName] LIKE @Start)
RETURN
GO
 
CREATE PROCEDURE [dbo].[Contact_FindFirstStartsWith]
(
 @Start [nvarchar] (256)
)
AS
SET NOCOUNT ON
SELECT DISTINCT [Contact].[Id], [Contact].[ContactName], [Contact].[ContactFirstName], [Contact].[ContactAge], [Contact].[ContactBirth], [Contact].[ContactCategory_Id], [Contact].[_trackLastWriteTime], [Contact].[_trackCreationTime], [Contact].[_trackLastWriteUser], [Contact].[_trackCreationUser], [Contact].[_rowVersion]
    FROM [Contact]
    WHERE ([Contact].[ContactName] LIKE @Start)
RETURN
GO
 
Bien entendu on a deux méthodes bien pratiques ajoutées à la couche métier
CFContactsProcedures-copie-1.JPG  
Le choix de l’utilisation de IList,ICollection à la place des generics permet certes l’utilisation du projet en .NET 1.0 mais on ne dispose pas des méthodes de filtre très pratiques (Find,FindAll)
Plusieurs solutions sont alors possibles :
-          Soit créer ses propres méthodes de filtre qui répondront au besoin
-          Soit créer des méthodes recevant un predicate
 
 
C’est donc une grosse erreur, espérons qu’à l’avenir les generics seront utilisés, car avec .NET 3.0, on risque de ne même pas pouvoir utiliser les requêtes Linq To Objects
 
 
Par Romagny13
Ecrire un commentaire - Voir les commentaires - Recommander
Premiers points sur Code Fluent

Points négatifs :
-          La gestion de la connexion à SQL Server  est trop transparente (gérée par CodeFluent.Runtime.dll), 
pas de fichier de configuration (app.config ou web.config)
-          De ce fait il est conseillé de nommer la base de données avec le même namespace utilisé, la chaine de connexion se basant dessus et étant générée dynamiquement
-          seul SQL Server est pris en charge (à l’heure actuelle, il ne me semble pas possible de se connecter à Access par exemple même si je mets le conditionnel-CodeFluent.Producers.SqlServer.dll)
-          un certains nombre de champs/properties (rowVersion,entityState,etc.) ainsi que pour la base de données, sont générés en « plus »,ce qui impose d’ajouter un peu de code si on ne désire pas qu’ils soient affichés (attribut        [System.ComponentModel.Browsable(false)])
-          un seul constructeur par défaut, on est obliger soit de le coder par soi-même soit définir chaque property une à une
-          les requêtes vers le server  sont parfois assez longues
 
Avantages :
-          c’est l’outil à l’heure actuelle qui m’a le plus impressionné par l’apport
-          la gestion des relations : on n’a non pas une clé étrangère mais la l’objet de la relation en lui-même)(relations 0..1,1..1)
-          un sytème de génération simple,très complet,et rapide
-          une seule dll à ajouter au projet, cela change d’Entreprise Library par exemple (personnellement j’aime que le code généré soit le plus proche possible de ce que j’aurais obtenu en tapant tout « à la main » et ne pas avoir « 50 » librairies à ajouter au projet, qui ne serviront pas forcément toutes ou très peu en comparaison)

>> http://www.softfluent.com/codefluent_features_fr.aspx

CodeFluentMethods.jpg
Méthodes pour charger
J’utilise toujours mon exemple de gestion de Contacts
>dans les classes Collections
           ContactCategory oContactCategory = ContactCategory.Load(3);
 
            // Methodes retournant un IDataReader
            IDataReader reader = ContactCollection.DataLoadAll();
            IDataReader reader = ContactCollection.DataLoadByContactCategory(oContactCategory);
            IDataReader reader = ContactCollection.PageDataLoadAll(null);
            IDataReader reader = ContactCollection.PageDataLoadByContactCategory(oContactCategory);
 
            // Methodes retournant une collection
            ContactCollection Contacts = ContactCollection.LoadAll();
            ContactCollection Contacts = ContactCollection.LoadByContactCategory(oContactCategory);
            ContactCollection Contacts = ContactCollection.PageLoadAll(1, 1);
 
 
>dans les classes « unitaires »
           // retournant un objet metier
            Contact oContact = Contact.Load(1);
            Contact oContact = Contact.LoadByEntityKey("1");
 
Ajout
>Classes collections
            Contact c = new Contact();
            c.ContactName = "Durand";
            c.ContactFirstName = "Paul";
            c.ContactAge = 50;
            c.ContactCategoryId = 1;
 
            bool result = ContactCollection.Insert(c);
           
>Classes unitaires
            Contact c = new Contact();
            c.ContactName = "Durand";
            c.ContactFirstName = "Paul";
            c.ContactAge = 50;
            c.ContactCategoryId = 1;
 
           bool result = Contact.Save(c);
 
Update
>Classes collections
           Contact c = Contact.LoadById(3);
            c.ContactName = "DUPONND";
            c.ContactFirstName = "Paul";
            c.ContactAge = 50;
            c.ContactCategoryId = 1;
 
            bool result = Contact.Save(c);
>Classes unitaires
            Contact c =Contact.LoadById(3);
            c.ContactName = "DUPOND";
            c.ContactFirstName = "Paul";
            c.ContactAge = 50;
            c.ContactCategoryId = 1;
 
           bool result = Contact.Save(c);
Delete
>Classes collections
           Contact c =Contact.LoadById(3);
            ContactCollection.Delete(c);
>Classes unitaires
           Contact c =Contact.LoadById(3);
            bool result = Contact.Delete(c);
 
 
Travail sur la couche métier puis mise à jour
On peut tout à fait travailler « en deconnecté » on pourrait dire, c'est-à-dire charger une collection,puis faire des ajouts,modification,suppression, et enfin faire la mise à jour vers la base de données,(un peu comme ce que l’on fait avec un DataSet), ce grâce à la gestion des etats(rowVersion ,entityState)
 
Exemple :
1 je charge la collection de contacts
2 j’ajoute un contact à la couche métier(c'est-à-dire donc la colllection)
3 je sauve les changements(le contact sera ajouté en base de données)
            ContactCollection Contacts = ContactCollection.LoadAll(); 
          
            Contact c = new Contact();
            c.Id = 5;// il faut definir la cle ici même pour une cle auto incrementée
            c.ContactName = "SCHACHT";
            c.ContactFirstName = "Eric";
            c.ContactAge = 30;
            c.ContactCategoryId = 1;
            Contacts.Add(c);
 
            Contacts.SaveAll();
 
Ce système parait certes intéressant, mais j’ai tendance à le fuir personnellement car on multiplie les chances de conflits lors de la mise à jour
Par Romagny13
Ecrire un commentaire - Voir les commentaires - Recommander
Code Fluent - Initiation

Code Fluent est une solution développée par des experts .NET   (Soft Fluent)

une série d’articles pourraient être postés car je vais étudier plus en profondeur les possibilités offertes
J’utilise ici mon classique exemple gestion de contacts très simple pour bien comprendre
1 – définition des fichiers Xml
2 tables/classes : Contact et ContactCategory
CFContacts .xml
<cf:project xmlns:cf="http://www.softfluent.com/codefluent/2005/1"
                  xmlns:cfpc="http://www.softfluent.com/codefluent/producers.cache/2005/1"
                  defaultNamespace="CFContacts"
                  persistencePropertyNameFormat="{1}"
                  defaultKeyPropertyTypeName="int">
 <!-- inclut le fichier CFContactsProducerAll.xml -->
 <cf:import path="CFContactsProducerAll.xml" />
 <!-- definition de 2 entités -->
 <Contact>
    <Id/>
    <ContactName/>
    <ContactFirstName/>
    <ContactAge typeName="int"/>
    <ContactBirth typeName="datetime"/>
    <ContactCategory typeName="ContactCategory"/>
 </Contact>
 <ContactCategory>
    <Id/>
    <ContactCategoryLabel/>
 </ContactCategory>
</cf:project>
 
CFContactsProducerAll.xml 
seront générés :
- la base de données SQL ServerCFContacts  avec tables,relations,procédures stockées,...
- les classes du projet Visual Studio
<cf:project xmlns:cf="http://www.softfluent.com/codefluent/2005/1"
      defaultNamespace="CFContacts">
 <cf:producer typeName="CodeFluent.Producers.SqlServer.SqlServerProducer, CodeFluent.Producers.SqlServer">
    <cf:configuration
                  targetDirectory="c:/Target/Persistence"
                  connectionString="server=.;database=CFContacts;Integrated Security=true">
    </cf:configuration>
 </cf:producer>
 <cf:producer typeName="CodeFluent.Producers.CodeDom.CodeDomProducer, CodeFluent.Producers.CodeDom">
    <cf:configuration
                  targetDirectory="c:/Target/Model"
                  outputName="CFContacts.Model.dll">
    </cf:configuration>
 </cf:producer>
</cf:project>
 
 
2 – Génération
Lancer CodeFluent command prompt  .. Puis ..
CodeFluent.Build <chemin vers fichier.xml>
Dans mon cas
CodeFluent.Build  « C:/Documents and Settings/romagny/Mes documents/Visual Studio 2005/Projects/CFContacts/CFContacts.xml »

CodeFluent2.JPG

CFContacts.JPG  
3- projet
Ajouter soit la dll générée du projet soit les classes
+ Ajouter une référence à la dll CodeFluent.Runtime.dll (présent dans le répertoire d’installation de CodeFluent)
Premier constat : nous avons des classe collections et des classes unitaires 
Celles ci s'occupent (en une seule et même classe) à la fois 

>> de l'accès à la base de données via des méthodes static (les classes collections retournant des collections,les classes unitaires des instances)
>> du filtre et du trie des objets métiers
De plus Code Fluent dispose de son propre language de requetage le CFQL
exemple :
public CFContacts.Contact GetItem(int id)
        {
            if ((id == -1))
            {
                throw new System.ArgumentNullException("id");
            }
            CFContacts.Contact i = ((CFContacts.Contact)(this.BaseTable[id]));
            return i;
        }
 
public static System.Data.IDataReader PageDataLoadAll(CodeFluent.Runtime.PageOptions pageOptions)
        {
            CodeFluent.Runtime.CodeFluentPersistence persistence = CodeFluentContext.Get(CFContacts.Constants.CFContactsStoreName).Persistence;
            persistence.CreateStoredProcedureCommand("Contact_LoadAll");
            if ((pageOptions != null))
            {
                System.Collections.IEnumerator enumerator = pageOptions.OrderByArguments.GetEnumerator();
                bool b;
                int index = 0;
                for (b = enumerator.MoveNext(); b; b = enumerator.MoveNext())
                {
                    CodeFluent.Runtime.OrderByArgument argument = ((CodeFluent.Runtime.OrderByArgument)(enumerator.Current));
                    persistence.AddParameter(string.Format("@_orderBy{0}", index), argument.Name);
                    persistence.AddParameter(string.Format("@_orderByDirection{0}", index), ((int)(argument.Direction)));
                    index = (index + 1);
                }
            }
            System.Data.IDataReader reader = CodeFluentContext.Get(CFContacts.Constants.CFContactsStoreName).Persistence.ExecuteReader();
            return reader;
        }
 
ClassDiagram1-copie-1.jpg
Par Romagny13
Ecrire un commentaire - Voir les commentaires - Recommander
CodeFluent - "fabrique logicielle orientée modèle" de Soft Fluent

Documentation,webcasts ,version évaluation 60j

http://www.softfluent.com/codefluent_home_fr.aspx
Par Romagny13
Ecrire un commentaire - Voir les commentaires - Recommander
Créer un blog sur over-blog.com - Contact - C.G.U. - Rémunération en droits d'auteur - Signaler un abus