Adott a következő feladat: egy hosszú és összetett XML fájlt kell relációs adatbázisba tenni. Természetesen XSD is van hozzá. Többféle lehetőség is kínálkozik, a cikksorozat ezeket fogja sorban elemezni:
1. XML feldolgozása DataSet segítégével
Létrehozunk egy dataset objektumot, megadjuk neki a sémát, majd egyszerűen beleolvassuk az XML fájlt:
Dim dsXML As DataSet
dsXML.ReadXmlSchema(xsd_doksi)
dsXML.ReadXml(xml_doksi, XmlReadMode.ReadSchema)
Ezzel létrejön a dataset objektum a memóriában, sok-sok táblával (ha elég összetett volt a forrás xml, de általában elég összetett).
Ha ezt a datasetet megadjuk egy datagridview objektum forrásának, akkor bele is kukkanthatunk az eredménybe, ha megadjuk a datagridview forrásának a dataset valamelyik tábláját.
DataGridView1.DataSource = dsXML.Tables(0)
majd
DataGridView1.DataSource = dsXML.Tables(1)
...stb.
Az eredmény: szépen látszódnak a táblák amiket készített. A baj az, hogy a forrás XML bizony sok keresztbe-kasul relációt is tartalmazott, amik sajnos nem látszanak. A relációkat a friss táblák úgy őrizték meg, hogy belepakolt a mezők mellé plusz mezőket, amik "_Id" végződésű neveket kaptak.
Valamiért annak ellenére hogy benne vannak ezek az automatikusan létrejött "segéd" _Id mezők, nem jelennek meg a datagridview automatikus nézetében. Ha mindenképp látni szeretnénk, némi rábeszélésre egy textboxban ki tudjuk iratni őket:
DataGridView1.DataSource = dsXML.Tables(0)
For i = 0 To dsXML.Tables(0).Columns.Count - 1
TextBox1.Text = TextBox1.Text & vbCrLf & " " & dsXML.Tables(0).Columns(i).ColumnName
Next
Így láthajuk, hogy mindenféle _Id végződésű mezőt pakolt hozzá a datagridview oszlopaihoz, így próbálva a relációkat valahogy megőrizni.
Ezzel két problémám van:
1. Nyomokban sincs köze a szerkezetnek az XSD fájlban definiált szerkezethez, márpedig az adatbázis, amibe majd tenni kell az adatokat, illendő lenne, ha olyan szerkezetű lenne, ahogyan ezt az XSD előírta. A dataset táblanevei a nodoknak felelnek meg, és nem az xsd fájlban definiált struktúrának. (Ez persze várható volt, de reménykedtem...)
2. Követhetetlenek a relációk.
Ez a megoldás valószínűleg kiválóan működik egy olyan XML fájlra, ahol sok egyforma, de nem túl összetett szerkezetű adat van. Például erre az xml-re:
<Autok>
<Auto>Trabant</Auto>
<Auto>Mercedes</Auto>
</Autok>
Nagyszerűen működik, pont azt látom a gridben amit kell - de az élet sajnos nem ilyen XML fájlokat sodor a közelünkbe, hanem hosszú, bonyolult, ismétlődő, egymásba ágyazott, keresztbe hivatkozó, stb.
Próbáljuk meg a relációkat valahogy tudomására hozni a datasetnek, hogy barátságosabb formában láthassuk a datagridview-ban az adatokat. Van két táblánk a datasetben, a mezo_Id a közös bennük, és a két tábla összekapcsolásával szeretnénk kiíratni néhány mezőt:
Dim egyiktabla = dsXML.Tables("egyiktabla").AsEnumerable()
Dim masiktabla = dsXML.Tables("masiktabla").AsEnumerable()
Dim vegyesnezet = egyiktabla.Join(masiktabla, Function(masik) masik.Field(Of Object)("mezo_Id"), _
Function(egyik) egyik.Field(Of Object)("mezo_Id"), _
Function(egyik, masik) _
New With {.eredmenymezo1 = egyik.Field(Of Object)("mezonev1"), .eredmenymezo2 = egyik.Field(Of Object)("mezonev2")})
És végül adjuk meg a lekérdezést a datagridview forrásának, hogy láthassuk az eredményt:
DataGridView1.DataSource = vegyesnezet.ToList
Arra nagyon figyelnünk kell, hogy a típusokat helyesen adjuk meg(a Field(Of [típus]) esetében), mert ha a típus nem megfelelő, akkor csak hibaüzenetet fogunk kapni.
Remek példa van az MSDN-en erről itt is: http://msdn.microsoft.com/en-us/vbasic/bb738025.aspx
Egyetlen gondom volt vele, mégpedig ezzel az utasítással:
ObjectDumper.Write(smallOrders)
Ez az ObjectDumper ugyanis semelyik névtérben nem leledzett nálam, némi utánajárás után kiderült, hogy ez egy spéci osztály, ami letölthető. Le is töltöttem, de órák alatt sem sikerült munkára bírnom, meg a kódomba sem szerettem volna beemelni mindenféle kódnövesztőt, az ObjectDumper irodalma is elég szerény, így addig kísérleteztem, amíg sikerült kiküszöbölnöm a használatát, mégpedig a
.ToList
utasítással. (Biztosan vesztettem ezzel nagyon jó dolgokat amiket az ObjectDumper tud, a ToList meg nem, de még nem jöttem rá mik ezek, én elégedett voltam a látvánnyal ami a DataGridView-ban megjelent)
Ha ezzel a módszerrel addig gyűrjük a datasetet, amíg pontosan azokat a relációkat csikartuk ki belőle, ahogyan majd az adatokat bele akarjuk tenni az adatbázisba, akkor egy ilyen lekérdezés eredményét már könnyedén beletehetjük egy (vagy több) SQL utasítással az adatbázisba.