1. Microsoft Silver Partner ISV

    Kategori: .NET,Meddelelser | Tags:
    Skrevet af d. 2011-05-11 kl. 13:23:59, sidst opdateret d. 19. maj 2011 kl. 11:26:47

    Hinnerup Net er blevet udnævnt som Microsoft Silver Partner ISV (Independent Software Vendor) med speciale i softwareløsninger.

    Vi har i Hinnerup Net investeret såvel tid, energi og penge i at skærpe og målrette vore kompetencer indenfor Microsoft’s teknologier og platforme, og vi belønnes nu for den ekspertise og viden vi har opnået.

    Dette betyder du som kunde kan regne med at du får:

    • leveret kvalitetsløsninger indenfor Microsoft’s teknologi og platform
    • softwareudviklere med optimal softwarekendskab og kompetence
    • et samarbejde med en softwareleverandør der er en anerkendt Microsoft Partner

    ADO.NET vs. LinQ to SQL

    Kategori: .NET,Programmering
    Skrevet af d. 2011-03-23 kl. 10:47:39, sidst opdateret d. 26. maj 2011 kl. 12:29:02

    Fordele

    Der er flere fordele ved LinQ to SQL over ADO.NET. Nogle eksempler er følgende:

    • Ingen brug for at skrive triviel kode til databasekald.
    • Stærke typer gør at flere fejl fanges ved compile-time.
    • Visual Studio intellisense resulterer i kortere udviklingstid.
    • Lambda expressions resulterer i kortere udviklingstid og mere kompakt og forståelig kode.

    Hastighed

    I de fleste situationer er der ikke grund til at spekulere på om LinQ to SQL har værre performance end ADO.NET. De største performanceforbedringer findes typisk tre andre steder:

    1. Udførelse af operationer på data på SQL serveren når det er muligt.
    2. Benyttelse af fornuftige indeks og evt. midlertidige tabeller
    3. Reducering af mængden af data som skal overføres til applikationen.

    Opsætning af LinQ to SQL database context

    Opret et projekt af typen Console.

    Højreklik på projektet, vælg Add New Item -> Data -> LINQ to SQL Classes. Sæt Name til “MyDatabase.dbml” og klik Add.

    Klik på Server Explorer.

    Højreklik på Data Connections og vælg Add Connection…

    Skriv “.\SQLEXPRESS” i Server name og klik på Refresh. Der bør ikke meldes om fejl.

    Skriv “MyDatabase” i New database name og klik OK.

    Opret en tabel Customers med følgende struktur:

    create table Customers (ID int NOT NULL IDENTITY, FirstName nvarchar(100), LastName nvarchar(100), BirthDate datetime, Active bit, constraint Customers_ID primary key (ID))
    

    Træk tabellen Customers over i MyDatabase.dbml vinduet og gem filen.

    Indsættelse af entiteter med ADO.NET

    Vi fodrer et SqlCommand objekt med et SQL statement og udfører kommandoen på et åbent SqlConnection objekt.

    private static void AddCustomer(SqlConnection connection, string firstName, string lastName, DateTime birthDate, bool active)
    {
        var command = new SqlCommand("insert into Customers (FirstName, LastName, BirthDate, Active) VALUES (@FirstName, @LastName, @BirthDate, @Active)", connection);
        command.Parameters.Add(new SqlParameter("@FirstName", firstName));
        command.Parameters.Add(new SqlParameter("@LastName", lastName));
        command.Parameters.Add(new SqlParameter("@BirthDate", birthDate));
        command.Parameters.Add(new SqlParameter("@Active", active));
        command.ExecuteNonQuery();
    }
    

    Som kan ses, så kræver det en del triviel kode.

    Udtræk af entiteter med ADO.NET

    Vi fodrer en connection string til et SqlConnection objekt, åbner forbindelsen og indsætter nogle entiteter. For at hente entiteterne frem igen, fodrer vi SQL til SqlCommand, opretter en SqlDataReader, gennemgår hver række samt henter værdien af hvert felt vha. feltnavnindeks. Læg mærke til det trivielle kode vi benytter til bare at konvertere til den rette datatype. Koder vi fejl her, så opdager vi det sandsynligvis først ved run-time ved test (hvis vi da sørger for at teste kodevejen med fejlen) eller (endnu værre) ved run-time i produktionmiljøet. Typefejl opstår ikke så ofte med LinQ to SQL, men kan ske hvis .dbml filen ikke er opdateret til databasestrukturen.

    static void Ado()
    {
        using (var connection = new SqlConnection(ConnectionString))
        {
            connection.Open();
            AddCustomer(connection, "Hans", "Christian", new DateTime(1960, 10, 4), true);
            AddCustomer(connection, "George", "Kohl", new DateTime(1974, 5, 7), true);
            AddCustomer(connection, "Marie", "Muse", new DateTime(1986, 2, 8), false);
            var command = new SqlCommand("select FirstName, LastName, BirthDate, Active from Customers", connection);
            var customersReader = command.ExecuteReader(CommandBehavior.CloseConnection);
            while (customersReader != null && customersReader.Read())
                Console.WriteLine(String.Format("{0} {1} {2} ({3})",
                    (string)customersReader["FirstName"],
                    (string)customersReader["LastName"],
                    ((DateTime)customersReader["BirthDate"]).ToString("dd-MM-yyyy"),
                    (bool)customersReader["Active"]));
        }
    }
    

    Indsættelse og udtrækning af objekter med LinQ to SQL

    Med LinQ to SQL opretter vi et MyDatabaseDataContext objekt som svarer til SqlConnection objektet i ADO.NET. Vi fodrer objektet med en connection string.

    Som det kan ses så er koden til indsættelse så triviel at vi ikke behøver at pakke det ind i egen metode for at få overskuelig kode. Det kræver kun to linjer kode. Vi opretter et Customer-objekt, fodrer objektet til <datakontekst>.<objekt-type>s.InsertOnSubmit() samt kalder <datakontekst>.SubmitChanges() for at igangsætte ændringerne i databasen.

    Med LinQ to SQL kan vi udtrække data på to måder.

    1) SQL lignende syntax. Struktur:

    Denne form kan være god at bruge i de lidt mere komplekse tilfælde med joins. LinQ to SQL sørger for at hentes mindst muligt data fra databasen.

    var variable1 = from <id1> in <datakontekst>.<tabelnavn1>s
                    [join <id2> in <datakontekst>.<tabelnavn1>s on <id1>.<key1> equals <id2>.<key2>]
                    [where]
                    [<id1>.<feltnavn1>.<metode>(<parametre>)]
                    [&& <id1>.<feltnavn2> <operator> <værdi>]
                    [orderby <id1>.<feltnavn1> [ascending|descending]]
                    select <id1>;
    

    Hvis meget kompleks datamanipulation eller udtræk er nødvendigt, så kan man med fordel oprette en stored procedure og kalde denne ved brug af LinQ to SQL. Metoder til at kalde stored procedures placeres på datakontekstobjektet.

    Det er også muligt at instansiere et objekt af en type som opbygges on-the-fly ved at ændre “select <id1>” til:

    select new
    {
        <feltnavn1> = <udtryk>,
        <feltnavn2> = <udtryk>
    };
    

    2) Metodekald med lambda expressions. Struktur:

    var customers2 = <datakontekst>.<tabelnavn>s.Where(<id> => [<id>.<feltnavn>.<metode>(<parametre>)] <operator>
    [<id>.<feltnavn> <operator> <value>]);
    

    Vi kan nu bare iterere igennem resultatsættet som består af stærkt typede objekter f.eks. med foreach. Eksempel:

    static void Linq()
    {
        using (var db = new MyDatabaseDataContext(ConnectionString))
        {
            db.Customers.InsertOnSubmit(new Customer { FirstName = "LinQ", LastName = "Rocks", BirthDate = new DateTime(2006, 4, 11), Active = false});
            db.SubmitChanges();
    
            var customers1 = from c in db.Customers
                            where c.FirstName.StartsWith("H") &&
                                  c.Active == true
            orderby c.BirthDate ascending
                            select c;
    
            foreach (var customer in customers1)
                Console.WriteLine(String.Format("1: {0} {1} {2} ({3})",
                    customer.FirstName,
                    customer.LastName,
                    customer.BirthDate.ToString(),
                    customer.Active));
    
            var customers2 = db.Customers.Where(c => c.FirstName.StartsWith("H") && c.Active == true);
            foreach (var customer in customers2)
                Console.WriteLine(String.Format("2: {0} {1} {2} ({3})",
                    customer.FirstName,
                    customer.LastName,
                    customer.BirthDate.ToString(),
                    customer.Active));
    
            var customers3 = from c in db.Customers
                            where c.Active == false
                            select new
                            {
                                FullName = c.FirstName + " " + c.LastName,
                                BirthDate = c.BirthDate,
                            };
    
            foreach (var customer in customers3)
                Console.WriteLine(String.Format("3: {0} {1}",
                    customer.FullName,
                    customer.BirthDate.ToString()));
        }
    }
    

    Resultatet fra Linq() metoden er:

    1: Hans Christian 04-10-1960 00:00:00 (True)
    2: Hans Christian 04-10-1960 00:00:00 (True)
    3: Marie Muse 08-02-1986 00:00:00
    3: LinQ Rocks 11-04-2006 00:00:00
    

    LINQ to XML

    Kategori: .NET,Programmering
    Skrevet af d. 2010-06-04 kl. 10:34:04, sidst opdateret d. 27. maj 2011 kl. 11:38:54

    Language-Integrated Query (LINQ) er en teknologi der tillader query-egenskaber direkte i C#. I query-form ligner det SQL i syntax og opbygning. Alternativet er method-syntax som vi ikke vil bruge tid på i dette indlæg. Til de interesserede kan forskellen mellem query og method syntax ses her: http://msdn.microsoft.com/en-us/library/bb397947.aspx. MS anbefaler at man bruger query syntax alle de steder man kan, frem for method syntax.

    LINQ to XML er en del af LINQ, og er designet til at trække data ud af xml, fra eksempelvis en fil.

    Vi skal bruge namespacet ”System.Xml.Linq”. Dette namespace indeholder klasser som XDocument, XElement, XAttribute og XNode. Det er nogle af disse vi bruger i vores query.

    LINQ syntaksen minder meget om SQL og kan ses her:
    http://msdn.microsoft.com/en-us/library/bb308959.aspx#linqoverview_topic5

    Lad os springe ud i det.

    Lad os først finde noget XML vi selektivt vil trække data ud af. Følgende er et log udtræk fra SVN:

    <?xml version=”1.0″?>
    <log>
      <logentry revision=”200″>
        <author>Lars</author>
        <date>2010-06-03T08:24:19.329726Z</date>
        <paths>
          <path action=”M”>/sti/Upload.ascx.cs</path>
          <path action=”D”>/sti/Projekt.csproj.user</path>
        </paths>
        <msg>Changes to upload path handling</msg>
      </logentry>
      <logentry revision=”199″>
        <author>Lars</author>
        <date>2010-05-31T14:30:23.080950Z</date>
        <paths>
          <path action=”M”>/sti/Database.mdf</path>
          <path action=”M”>/sti/Database.ldf</path>
        </paths>
        <msg>Shrinked database again</msg>
      </logentry>
      <logentry revision=”198″>
        <author>Lars</author>
        <date>2010-05-31T13:59:33.689391Z</date>
        <paths>
          <path action=”A”>/sti/Projekt.sln</path>
          <path action=”A”>/sti/Projekt.suo</path>
        </paths>
        <msg>VS2010 Solution files.</msg>
      </logentry>
      <logentry revision=”197″>
        <author>Sral</author>
        <date>2010-05-28T07:10:51.597195Z</date>
        <paths>
          <path action=”M”>/sti/</path>
        </paths>
        <msg>Added files/folders to ignore filter.</msg>
      </logentry>
    </log>
    

    Først tæller vi alle log entries grupperet på author. Det kan klares således:

    var output = from logentry in SvnLog.Elements("logentry")
        group logentry by (string) logentry.Element("author")
        into logentries
        select new {
            Author = logentries.Key,
            Entries = logentries.Count()
        };
    

    Vi piller querien fra hinanden og ser på de enkelte dele.

    from logentry in SvnLog.Elements("logentry")

    Dette statement returnerer en IEnumerable liste af XElementer indeholdende alle under-noder i hvert <logentry> element. Disse bliver så placeret i en variabel kaldet “logentry”.

    group logentry by (string) logentry.Element("author") into logentries

    Vi grupperer her på datasættet fra før med en under-node i <logentry> ved navn <author>. Note: Det er vigtigt at huske castet til string da de fleste klasser i System.Xml.Linq har custom type converters (http://msdn.microsoft.com/en-us/library/ayybcxe5.aspx).

    Et cast til string giver elementets værdi, hvor logentry.Element(“author”).ToString() ville give en string repræsentation af objektet.

    Til sidst placerer vi vores gruppering i en ny variable ved navn ”logentries”.

    select new { Author = logentries.Key, Entries = logentries.Count() };

    Her over laver vi en anonym type indeholdende vores fundne data (Anonymous Types: http://msdn.microsoft.com/en-us/library/bb397696.aspx)
    Logentries.Key er altid hvad man grupperer på. I dette eksempel laver vi en simpel count på de fundne værdier.

    Vi kører det igennem en foreach løkke:

    foreach (var d in output) {
         Console.WriteLine("{0}: {1} entries.", d.Author, d.Entries);
    }
    

    Resultat:

    Lars: 3 entries.
    Sral: 1 entries.

    Lad os prøve en lidt mere avanceret query med nestede selects.

    Vi prøver følgende: Vores query skal tælle attributen action (i <path>) grupperet på værdien. For at være endnu mere vanskelig grupperer vi også på author igen.
    Resultatet vi søger skulle gerne se sådan ud:

    Lars: A:2, M:3, D:1
    Sral: A:0, M:1, D:0

    Querien kommer til at se således ud:

    var data =
      from logentry
      in SvnLog.Elements("logentry")
      group logentry by (string)commit.Element("author")
        into logentries
        select new
        {
          Author = logentries.Key,
          Added = (
              from path in logentries.Elements("paths").Elements("path")
              where (string)path.Attribute("action") == "A"
              select path
          ).Count(),
          Modified = (
            from path in logentries.Elements("paths").Elements("path")
            where (string)path.Attribute("action") == "M"
            select path
          ).Count(),
          Deleted = (
            from path in logentries.Elements("paths").Elements("path")
            where (string)path.Attribute("action") == "D"
            select path
          ).Count()
        };
    

    Det første i querien ligner statementet fra før: vi grupperer blot på author. Inde i vores anonyme type har vi nu 3 næsten ens selects:

    from path in logentries.Elements("paths").Elements("path")

    Vi finder alle ”path” noder som vores gruppering i det ydre scope indeholder.

    where (string)path.Attribute("action") == "A"

    Af de fundne path noder, finder vi alle dem der har attributten ”A”.

    select path

    Dem der matcher vores where clause selecter vi, plus pakker det hele ind til sidst, så vi kan lave en Count() på det.

    foreach (var user in data) {
       Console.WriteLine("{0}: A:{1}, M:{2}, D:{3}",
          user.Author, user.Added, user.Modified, user.Deleted);
    }
    

    Og nu får vi det output vi søgte:

    Lars: A:2, M:3, D:1
    Sral: A:0, M:1, D:0


    Næste side >>>