Om een database te migreren en daarbij een aantal velden toe te voegen schrijf ik een programma dat elk record uit de originele database plukt en deze opslaat in de nieuwe database. De database bestaat uit 3 tabellen. Een 'hoofdtabel' met een 0..* relatie naar de twee 'childtabellen'.
Om het simpel te houden en in memory te kunnen evalueren trek ik alle data in delen uit de originele tabel op een volgende manier:
De oldObjectes worden per aantal 'bufferSize' opgehaald als ze nog niet geprocessed zijn (want 'migrated==null'), geanalyseerd, naar een nieuwe database ge-insert en vervolgens doe ik:
De loop draait opnieuw tot oldObjects.Count == 0.
Er gaat echter iets fout met het Entity Framework in dit alles. Als ik tel hoeveel childs er gekoppeld zijn na het doorlopen van alle records uit de hoofdtabel dan mis ik er soms (!!) een aantal. Ik weet dat ik uit 168 hoofdrecords 194 child1's en 3614 child2's moet hebben. Soms klopt dit, meestal niet. Er zijn wel altijd het verwacht aantal hoofdrecords van 168 aanwezig!
In de tabel met hoofdrecords zitten in het echt 660.000 entries, in child1 zitten er 194 en in child2 zitten er 8.6 miljoen. Na heel wat hoofdbrekens ben ik erachter gekomen dat elk hoofdrecord met alleen een child1 of alleen een child2 of zonder childs juist worden geprocessed. De problemen komen voor bij de records zie zowel child1 als child2 records hebben. Bij de records waarvan het fout gaat en niet zowel de child1's en childs2's aanwezig zijn is in dat geval wel altijd een van beide childs aanwezig. OF de childs1's zijn er dan OF de childs2's (en voor zo ver ik weet ook allemaal van dat type).
Ik heb al vanalles geprobeerd en het probleem lijkt te zitten in het samen gebruiken van meerdere 'includes' en de 'take' en in het Entity Framework. Via de MSSQL database profiler is de query die EF naar de database stuurt elke keer gelijk. Zowel in het foute als goede geval dus. Zonder de 'take' werkt het in de test ook altijd goed, maar dat kan niet op de echte data want die tabellen zijn veel te groot.
Echter, zonder de 'include' mee te geven werkt het voor zo ver ik nu kan zien wel altijd goed. Misschien is het een eigenschap van .net 4. Omdat ik de zaak via ToList omzet naar een in memory lijst verwacht ik voor de child tabellen een '.Include' te moeten geven. Zonder de includes kwam er geen data in (weet ik niet zeker, misschien lazy-loadde hij het toch wel, maar een 'include' is expliciet en voorkomt juist lazy loading en lege records!).
Een andere test met een tabel met bijna 600.000 records waaraan 0 of 1 child hangt wordt met ditzelfde mechanisme zonder enig probleem volledig overgezet.
Iemand inzicht in wat hier gebeurt of met hetzelfde bijltje gehakt?
Edit2:
Dit lijkt er misschien op maar geen oplossing omdat ik de .Take() niet buiten de .ToList() kan plaatsen: http://stackoverflow.com/...with-skip-take-load-issue
Om het simpel te houden en in memory te kunnen evalueren trek ik alle data in delen uit de originele tabel op een volgende manier:
code:
1
2
3
4
5
6
| var oldObjects = oldDb.tblMain .Include("tblChild1") .Include("tblChild2") .Where(x => x.Migrated == null) .Take(bufferSize) .ToList(); |
De oldObjectes worden per aantal 'bufferSize' opgehaald als ze nog niet geprocessed zijn (want 'migrated==null'), geanalyseerd, naar een nieuwe database ge-insert en vervolgens doe ik:
code:
1
2
3
| foreach (var oldTourDataObject in oldTourDataObjects) oldTourDataObject.Migrated = (byte)MIGRATIONSTEPS.MIGRATION_COMPLETE; oldDb.SaveChanges(); |
De loop draait opnieuw tot oldObjects.Count == 0.
Er gaat echter iets fout met het Entity Framework in dit alles. Als ik tel hoeveel childs er gekoppeld zijn na het doorlopen van alle records uit de hoofdtabel dan mis ik er soms (!!) een aantal. Ik weet dat ik uit 168 hoofdrecords 194 child1's en 3614 child2's moet hebben. Soms klopt dit, meestal niet. Er zijn wel altijd het verwacht aantal hoofdrecords van 168 aanwezig!
In de tabel met hoofdrecords zitten in het echt 660.000 entries, in child1 zitten er 194 en in child2 zitten er 8.6 miljoen. Na heel wat hoofdbrekens ben ik erachter gekomen dat elk hoofdrecord met alleen een child1 of alleen een child2 of zonder childs juist worden geprocessed. De problemen komen voor bij de records zie zowel child1 als child2 records hebben. Bij de records waarvan het fout gaat en niet zowel de child1's en childs2's aanwezig zijn is in dat geval wel altijd een van beide childs aanwezig. OF de childs1's zijn er dan OF de childs2's (en voor zo ver ik weet ook allemaal van dat type).
Ik heb al vanalles geprobeerd en het probleem lijkt te zitten in het samen gebruiken van meerdere 'includes' en de 'take' en in het Entity Framework. Via de MSSQL database profiler is de query die EF naar de database stuurt elke keer gelijk. Zowel in het foute als goede geval dus. Zonder de 'take' werkt het in de test ook altijd goed, maar dat kan niet op de echte data want die tabellen zijn veel te groot.
Echter, zonder de 'include' mee te geven werkt het voor zo ver ik nu kan zien wel altijd goed. Misschien is het een eigenschap van .net 4. Omdat ik de zaak via ToList omzet naar een in memory lijst verwacht ik voor de child tabellen een '.Include' te moeten geven. Zonder de includes kwam er geen data in (weet ik niet zeker, misschien lazy-loadde hij het toch wel, maar een 'include' is expliciet en voorkomt juist lazy loading en lege records!).
edit:
Wat hierboven staat lijkt niet waar. De hoofdrecords zitten in de list, maar de childs worden bij processen zo te zien gelazy-load. Dat is dus echt traag want voor elke child gaat hij naar de DB om die data op te halen ipv dat dat al in de platgeslagen memory-list zit...
Wat hierboven staat lijkt niet waar. De hoofdrecords zitten in de list, maar de childs worden bij processen zo te zien gelazy-load. Dat is dus echt traag want voor elke child gaat hij naar de DB om die data op te halen ipv dat dat al in de platgeslagen memory-list zit...
Een andere test met een tabel met bijna 600.000 records waaraan 0 of 1 child hangt wordt met ditzelfde mechanisme zonder enig probleem volledig overgezet.
Iemand inzicht in wat hier gebeurt of met hetzelfde bijltje gehakt?
Edit2:
Dit lijkt er misschien op maar geen oplossing omdat ik de .Take() niet buiten de .ToList() kan plaatsen: http://stackoverflow.com/...with-skip-take-load-issue
[ Voor 6% gewijzigd door Contagion op 06-08-2011 01:30 . Reden: 'include' toch nodig anders alsnog lazy-loading ]