Samarbejde mellem Hinnerup Net og kandidatstuderende fra Aarhus Universitet

Kategori: Projekt, Universitet
Skrevet af Michael Schøler d. 2010-06-15 kl. 09:52:41

En gruppe kandidatstuderende fra Institut for Informations- og Medievidenskab skrev i foråret 2010 eksamensopgave i samarbejde med Hinnerup Net.

I forbindelse med et eksamensprojekt i kurset IT-projektledelse har Hinnerup Net og de fire kandidatstuderende Rune Lykke, Mikkel Løfquist, Daisy Steffensen og Pernille Thorsen været så heldige at få lejlighed til at indgå i et samarbejde om en case.

Kurset de studerende fulgte omhandlede overordnet alle faserne i et projektforløb, hvor gruppen valgte at have særlig fokus på opstart, styring og udførelse af et IT-projekt. Her inddragedes forskellige ledelses- og projektmæssige teorier til at beskrive opstarten.

Basis for casen var det samarbejde Hinnerup Net har med LEGO, i forbindelse med de nuværende og kommende projekter, der er henholdsvis er i gang og under planlægning. I og med at Hinnerup Net og LEGO anvender SCRUM, blev dette desuden et af fokusområderne i opgaven.

Eksamensprojektet er tvedelt, således at opgaven i sig selv gøres til objekt for projektledelse, sideløbende med at der blev udarbejdet en analyse af den aktuelle case. Gennem casen opnås værdifuld indsigt i, hvad det vil sige at opstarte og lede et projekt samtidigt med, at der opnås et indblik i hvorledes en professionel organisation griber projektledelse og projektarbejde an.

For Hinnerup Net betyder samarbejdet med de fire studerende en mulighed for at holde fingeren på pulsen med hvad der sker i uddannelsesmiljøet, og det er naturligvis ikke uden en vis stolthed, at der bringes viden tilbage til en af de institutioner vi selv gennem tiden er uddannet fra.

Karaktererne for projektet er netop uddelt idag, og vi bringer hermed et stort tillykke til de fire 12′tals modtagere! Godt gået!

LINQ to XML

Kategori: .NET, Programmering
Skrevet af Lars Støttrup d. 2010-06-04 kl. 10:34:04, sidst opdateret d. 2010-06-26 kl. 20:39:17

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:

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
32
33
34
35
36
37
38
<?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:

1
2
3
4
5
6
7
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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