Tags

  • XML extension for entity framework

    by Frans van Ek | Nov 12, 2016

    XML field Extension for Entity framework

    The goal of this exercise is to investigate if it’s possible to get a typed selector on a XML field.

    In SQl there is a fieldtype XML. In this field it’s possible to store a serialized C# object. This mkes extentions on the data very easy but there is a down side to this. Query the field isn’t that straight forward. It will result in a string xml path selection. For instance:

    ((XMLContent.query('/SimpleItemSubObject/ID').value('.', 'bigint')  =  636142127126573004)


    So far it isn’t possible to make the query type strongly typed. And as I far as I could find it will not be implemented in the near future. So is it possible to do so ourselves?

    Final result has to be something like this:
     XMLFilter.Filter(x => x.ID, 636142127126573004, eCompairType.equals)

                    .And(x => x.Test.Name, "demo", eCompairType.less)

                    .And(x => x.Test.Time, DateTime.Now, eCompairType.less);


    And the apply it to the context

    var whereStatement = XMLFilter`

    .SetXMLColumnName<SimpleItem>(x => x.XMLContent)

    .GetQueryWhereClause();

      var db = new XMLTestContext();

      var items = GetItems<SimpleItem>(db.SimpleItems, whereStatement).ToList(); 

    So let’s get started:

    First we need to get a filter starting point. This is a generic type so we can reuse it for all types restricted the type is a class.

    public class XMLFilter<T> where T : class     { }


    In order to create a flexible selector there must be a possibility for and and or constructions. The way it will be implemented is to start with a or collection and place al the and filters in a or selection. This is similar to the way sql management studio works. Columns as or parts and rows inside column as And parts.

    public List<OrPart<T>> OrParts { get; set; } 


    The column on wich the filter must be applied;

     public List<OrPart<T>> OrParts { get; set; }

    public string XMlColumnName { get; private set; }


    to get the whereclause , there is an override on the ToString() function.

     

    public override string ToString()

            {

                var result = string.Empty;

                var orstring = string.Empty;

                foreach (var item in OrParts)

                {

                    result = string.Format("{0}{1}{2}"

    , result

    , orstring

    , item.ToString());

                    orstring = " or ";

                }

                return string.Format(result, XMlColumnName);

            }

     

            public string GetQueryWhereClause()

            {

                return this.ToString();

            }

     

    The override of the ToString() function will collect all the orparts and place the in a string separated bij the or statement. So the orpart will also have a override on the to string function to get this part of the filterstring.

    The hard part.

    Now in order to set the filter based upon the types properties there is a helper created. This helper is a static class to handle a lamda expression and make a kind of reflection on the property to get the correct xmlstring representation of the property. So how does this work?

     

    public OrPart<T> Filter(Expression<Func<T, object>> lambda, object value, eCompairType compairtype)

            {

                return Filter(PropertyFilterHelper<T>.GetPropertyInfo(lambda), value, compairtype);

            }



    First the xmlFilter has a function wich can handle a Lambda expression. This is done with a func. This func along with the filter value and the compairison type will be handled by the helper.

     

    public static PropertyFilter GetPropertyFilter(Expression<Func<T, object>> lambda, object value, eCompairType compairtype)

            {

                return new PropertyFilter { PropertyReference = GetPropertyInfo(lambda), Value = value, CompairType = compairtype };

            }


    Now the function has to translate the lamdaexpression to a propertyFilter. In this filter there is a list of properties. When the targeted propery is several levels deep into the object (with classes in classes by inheritance) the filter must name all the levels back to the rootobject in order to create the correct filter string for the xml.

    Building this list is the responsibility of the lambda analyser.

    This is a recursive method, to get to the root object.

     

    internal class LambaAnalyser<T>

        {

            private Expression<Func<T, object>> lambda;

            private List<PropertyInfo> result;

     

            public LambaAnalyser(Expression<Func<T, object>> lambda)

            {

                this.lambda = lambda;

                ClearResult();

            }

     

            internal IEnumerable<PropertyInfo> GetExpressionList()

            {

                if (lambda.Body.NodeType == ExpressionType.Convert)

                {

                    return GetPropertyListfor((lambda.Body as UnaryExpression).Operand as MemberExpression);

                }

     

                return GetPropertyListfor(lambda.Body as MemberExpression);

     

            }

     

            private IEnumerable<PropertyInfo> GetPropertyListfor(MemberExpression body)

            {

                ClearResult();

                if (body != null && body.Expression != null)

                {

                    AddPropertyInfoList(body);

                }

                return result;

            }

     

            private void ClearResult()

            {

                this.result = new List<PropertyInfo>();

            }

     

            private void AddPropertyInfoList(MemberExpression expression)

            {

                result.AddRange(GetPropertyListfor(expression.Expression as MemberExpression));

                result.Add((expression as MemberExpression).Member as PropertyInfo);

            }

     


    To get the list a bit more flexible it is wrapped in a properyrefence class.

    public class PropertyReference

        {

            public PropertyReference()

            {

                SetDefaults();

            }

     

            private void SetDefaults()

            {

                Properties = new List<PropertyInfo>();

            }

     

            public List<PropertyInfo> Properties { get; private set; }

        }


     

     

    So now we have a method that collects all the properties back to root, from the reference specified in the lambda expression. One small trick. Due to the structure of the Func function there is the possibility that the lambda will add an convert function in which the property reference is wrapped. So there is a if statement to deal with this.

    The homestretch

     

    Now we can find the properties in the lambda expression. And we can place them in a orpart we have make it possible to add items to the andparts within the orparts.

    Within this andpart there is a collection of propertyfilters to specifiy each filter.

    Within these propertyfilters the is some logic to convert types to the right sql represention.

    And that’s all.

    Let wrap it into a nuget bundle and share it.

     

    A few samples

    Entity in EF

    public class SimpleItem

        {

            public int Id { get; set; }

     

            public string Text { get; set; }

     

            [Column(TypeName = "xml")]

            [EditorBrowsable(EditorBrowsableState.Never)]

            [DebuggerBrowsable(DebuggerBrowsableState.Never)]

            public string XMLContent { get; set; }

     

     

            public SimpleItemSubObject GetSubObject()

            {

                return XMLContent.ConverToObject<SimpleItemSubObject>();

            }

     

     

            public SimpleItem SetSubObject(SimpleItemSubObject value)

            {

                XMLContent = value.ConvertToXmlString<SimpleItemSubObject>();

                return this;

            }

        }

     

     

     
     

    XML content base

    public class SimpleItemSubObject

        {

            public long ID { get; set; }

            public string Name { get; set; }

            public DateTime Date { get; set; }

     

            public long getal { get; set; }

            public TestObject Test { get; set; }

        }

     


     

    Subobject

     

     

     public class TestObject

        {

            public long ID { get; set; }

            public string Name { get; set; }

            public DateTime Time { get; set; }

        }

       


     

    Filters:

    Sample 1

     

    var XMLFilter = new XMLFilter<SimpleItemSubObject>();

     

                XMLFilter.Filter(x => x.ID, 636142127126573004, eCompairType.equals)

                    .And(x => x.Test.Name, "demo", eCompairType.less)

                    .And(x => x.Test.Time, DateTime.Now, eCompairType.less);

     

                var result = XMLFilter.SetXMLColumnName<SimpleItem>(x => x.XMLContent).GetQueryWhereClause();

     


    Sample 2

     

     

    var XMLFilter = new XMLFilter<SimpleItemSubObject>();

     

                XMLFilter.Filter(x => x.Test.Time, DateTime.Now.AddDays(-1), eCompairType.greater);

     

                var whereStatement = XMLFilter.SetXMLColumnName<SimpleItem>(x => x.XMLContent).GetQueryWhereClause();

                var db = new XMLTestContext();

                var items = GetItems<SimpleItem>(db.SimpleItems, whereStatement).Take(1).ToList();

     

        private DbSqlQuery<T> GetItems<T>(DbSet<T> dbset, string whereStatement) where T :class

            {

                var tsql = string.Format("{0} where {1} ", dbset.ToString(), whereStatement);

                return dbset.SqlQuery(tsql);

            }


     

     

     

     

     

     

     

     

     

    163 Comments
  • Clean code - Een must read voor elke developer

    by Frans van Ek | Apr 15, 2015
    Robert C. Martin heeft een boek geschreven over de codeerstylen en best practices als code geschreven worden. 

    Uitgangspunt is leesbaarheid van de code. Niet zozeer dat de compiler de code begrijpt maar de volgende ontwikkelaar die de code ziet. 

    Door het toepassen van een aantal simpele regels merkte ik dat:
    • Er minder bugs in mijn code zaten
    • Veranderingen sneller doorgevoerd konden worden.
    • Software onderhoudbaar werd. Geen spaghetti meer. Maar flexibele code die mee kon gaan met de veranderen wensen.
    • Andere programmeurs eenvoudig verder konden werken met mijn code
    • En geen snelheid ingeboet bij het schrijven van de code, sterker nog de snelheid ging omhoog.
    • geen hoofdpijn meer van het mentaal debuggen. Complete stack in je hoofd houden om het algoritme maar te kunnen begrijpen. Eenvoudige, testbare kleine functies.
    Een klein uittreksel van de uitgangspunten is hier te vinden. Absoluut geen reden om het boek niet te lezen. Integendeel, het is meer een uitnodiging om het boek te gaan lezen.



    172 Comments
  • fun met CSS en Javascript/jquery

    by Frans van Ek | Mar 05, 2015

    Fun

    Rotation speed Size speed Object size
    176 Comments
  • Javascript more type save

    by Frans van Ek | Mar 01, 2015

    Ok ok, ik ben een beetje bevooroordeeld. Ik wil intellisense als ik codeer. Het voorkomt namelijk dat ik type fouten maak en het gaat gewoon een stuk sneller.

    Er is nog een andere reden dat ik graag interllisense gebruik. Het kan er namelijk ook voor zorgen dat ik minder runtime errors heb en dus minder hoef te debuggen.

    Dit is dan ook de reden dat ik let op de mogelijkheid om runtime errors te voorkomen.Een van de punten die ik zelf niet prettig vindt aan javascript is dat veel string literals worden gebruikt als identificatie van elementen.

    Neem het volgende stuk je code.

     

    function update_div(id) {

            $("#" + id).html(newDate().getTime().toLocaleString()).parent().addClass("selected");

        }

        function clear_div(id) {

            $("#" + id).html("&nbsp").parent().removeClass("selected");

        }

        $(document).on("trigger_selection_main", function () {

            $(document).trigger("on_selection_main");

        }

        );

       

        $(document).on("trigger_selection_both", function () {

            $(document).trigger("on_selection_both");

        }

          );


    Wat opvalt zijn de vele stukjes tekst. Dit zijn niet stukken tekst maar strings met daarin de naam van een event of een Id van een element. Met een typefout in deze zal het betreffende stukje code niet werken.

    Verbetering.

    Door in de javascript een object aan te maken met daarin alle string teksten kunnen we vervolgens met intellisense gaan verwijzen. Een ander voordeel is dat bij het veranderen van de teksten het nu maar op één centrale plek aangepast moet worden.




     

    <script>

        var naming = {
            selectClass: "selected",
            triggerMainSelection: "trigger_selection_main",
            onSelectionMain: "on_selection_main",
            onSelectionBoth: "on_selection_both",
            triggerSelectionBoth: "trigger_selection_both",
        }



        function update_div(id) {

            $("#" + id).html(new Date().getTime().toLocaleString()).parent().addClass(naming.selectClass);

        }
        function clear_div(id) {
            $("#" + id).html("&nbsp").parent().removeClass(naming.selectClass);
        }

        $(document).on(naming.triggerMainSelection, function () {

            $(document).trigger(naming.onSelectionMain);
        }
        );

        $(document).on(naming.triggerSelectionBoth, function () {
            $(document).trigger(naming.onSelectionBoth);
        }
          );

       
    </script>

    De voordelen in mijn ogen zijn:

    -       Intellisense

    -       Minder kans op runtime errors

    -       Centrale locatie van de namen

    -       Code is beter te lezen.

    Nadelen :

    -        Iets meer coderen.

    175 Comments
  • Wie wil er ICT? Niemand.

    by Frans van Ek | Feb 27, 2014

    Op ICT alleen zit niemand te wachten. Het is hetzelfde als een hypotheek. Mensen willen een huis, maar wel een huis zonder hypotheek. Veel mensen hebben een hypotheek nodig om een huis te kunnen kopen. Deze mensen zullen blij zijn dat ze door middel van een hypotheek een huis kunnen kopen. Ook al is het dan eentje met een hypotheek. Maar nog steeds willen ze liever een huis zonder hypotheek.

    Dit vergelijk gaat ook als we kijken naar ICT. Ik ken maar weinig mensen die een computer kopen, puur en alleen omdat het een mooie computer is. Een computer die zo mooi is dat je hem in de kamer zet en er naar gaat kijken. Niet om er mee te werken! Ben je gek?  Daar is hij veel te mooi voor…..
    Maar voor het grootste deel van de mensen zal een computer een middel zijn om andere doelen te realiseren. ICT is daarmee dus een middel om iets te bereiken. Door middel van ICT kan een worden voorzien in een bepaalde behoefte. Maar ICT zelf is niet de behoefte. Hoe vaak wordt dit vergeten?

    Door de behoefte centraal te zetten kan deze behoefte veel beter ingevuld worden. Soms met ICT als dit de beste oplossing is maar ook zonder ICT als dat beter is. Ook in de zakelijke wereld is ICT een middel en geen doel. Het doel heiligt de middelen. Dus ICT moet alleen maar ingezet worden als het daadwerkelijk het doel dient en dan ook alleen als het de beste oplossing is.

    Toen de Amerikanen en Russen in de wedloop waren om de eerste mens in de ruimte te brengen, kwam een klein probleempje aan het licht. In gewichtloosheid schrijft een pen niet. Er is geen zwaartekracht die de inkt naar de punt zal drukken. Er moest dus iets voor verzonnen worden om de inkt toch eruit te krijgen. Miljoenen dollars zijn er door de Amerikanen geïnvesteerd om een technische perfecte pen te ontwikkelen die ook schrijft in gewichtloze toestand.
    De russen besloten na kort beraad om een potlood te gebruiken.

    Als een business proces slecht is dan helpt het niet om dit te gaan automatiseren. De chaos wordt dan alleen maar groter. Optimaliseer je proces en zet ICT in als het bijdraagt aan de optimalisatie van het proces. Dit bespaart veel geld en resulteert in een betere oplossing.

    De business kan vaak niet zonder de ICT. Maar de ICT kan ook niet zonder de business. Want ICT die alleen maar geld oplevert zijn schaars en misschien wel niet bestaand. Om op de vraag terug te komen. “Wie wil er ICT” is het antwoord; bijna iedereen. Maar dan als middel en niet als doel.

    179 Comments
  • C# classes

    by Frans van Ek | Feb 04, 2014
    In de vorige blogpost heb ik een toelichting geschreven voor de namespace declaratie.

    een vergelijk werd gemaakt tussen woonplaatsen en daarin bedrijven. Indeze blogpost ga ik verder bij het bedrijf in zo'n woonplaats. Dit kan worden gezien als een class.

    Een class is een beschrijving van een Element binnen het programma. Een element is een verzameling van ggevens en methodes diete maken hebben met dat type element.
    Zo zal een bedrijf een bedrijfsnaam hebben. Net zoals een KVK nummer. Een class beschrijft per type welke gegevens we vast wilen leggen. 

    Omdat programmeren iets anders is dan het opslaan van gegevens moeten we ook wat met die gegevens kunnen doen. Zo kan een bedrijf een procedure hebben om klachten af te handelen. zo'n procedure wordt binnen een class een methode genoemd.

    voorbeeld van een class

    namespace FirstProject
    {
        public class Bedrijf
        {
            public string BedrijfsNaam {get;set;}
            public string KVKNummer {get;set;}
            public void IndienenKlacht(string Klacht)
            {
               // hier komt de programmatuur voor het afhandelen van een klacht.
            }  
         }
    }

    We zien nu de namespace terugkomen. De regel met Namespace bepaald dat alles binnen de {} tekens valt binnen de genoemde namespace.
    in dit geval zal de volledige naam van de class worden FirstProject.Bedrijf.

    Binnen de namespace wordt een class gedefineerd met de typenaam Bedrijf. De accesmodifer Public kun je nu even vergeten daar kom ik later op terug.

    Binnen het type Bedrijf worden een aantal properties aangemaakt waarin we in het programma echte waardes kunnen stoppen. Belangrijk om te weten is dat het defineren van een class niets anders is dan het beschrijven van de mogelijkheden en eigenschappen van een bepaald type. Zie het als een bouwtekening. Daarop staat precies hoe het huis egbouwd wordt maar daarmee heb je nog geen huis. Dat moet eerst gebouwd worden. Gelukkig kan dat binnen c# heel snel en wordt instantieren genoemd. 



    500 Comments
  • C#: Namespaces, private, public, internal ...

    by Frans van Ek | Feb 03, 2014
    Als je gaat programmeren dan zul je al snel tegen deze termen aanlopen. Waar zijn ze voor bedoeld?

    Om te beginnen de term Namespace. Deze term verklaart in het engels al aardig wat de reden is. Kennelijk heeft er iemand over nagedacht, wat altijd een goed teken is.

    Namespace definieert een gedeelte waar toe alle andere namen behoren. Hierdoor kunnen we dezelfde namen op verschillende plekken gebruiken zonder dat er verwarring ontstaat.
    Dit is te vergelijken met twee woonplaatsen. Binnen deze woonplaatsen hebben de bedrijven namen. Door de naam van de woonplaats mee te nemen in de naam van het bedrijf kunnen bedrijven uit twee woonplaatsen altijd uitelkaar gehouden worden.

    woonplaats.naam => Amsterdam.Jumbo is iemand anders dan Rotterdam.Jumbo.

    In C# is dit ook zo ingedeeld. Verschillende elementen die bij elkaar horen worden in dezelfde namespace geplaatst. Hierdoor wordt het mogelijk om snel de juiste class, functie en property te vinden. Want de naamgeving van elementen houdt niet op bij de namespace alleen. Dit geldt voor elk element dat aangemaakt of gebruikt wordt binnen c#.
    Maar juist door het gebruik van de Namespace wordt het mogelijk om meerdere keren dezelfde naam te gebruiken voor een class. De namespace zorgt ervoor dat de classes uit elkaar gehouden worden.

    De juiste naam kiezen is dan ook belangrijk. In een toekomstige blog zal ik verder ingaan op naamgeving als ik Clean Code ga behandelen. 
      
    Voorbeelden van namespaces. 

    System;
    System.Collections.Generic;
    System.Linq;
    System.Text;
    System.Threading.Tasks;

    Bij een project dat aangemaakt wordt kan een nieuwe namespace ontstaan. Als het project aangemaakt wordt er een namespace ingesteld waar binnen alle elementen van het project gaan vallen.
    Zie - properties op project. 



    Je kunt de namespace hier aanpassen. Zorg er wel voor dat de namgeving logisch is. 



    441 Comments

Sitefinity Web Content Management