Hovedopgave Master i Informationsteknologi linien i Softwarekonstruktiona



Relaterede dokumenter
Database for udviklere. Jan Lund Madsen PBS10107

Object-Relational Mapping

Casper Fabricius ActiveRecord. O/RM i Ruby on Rails

Hvorfor skal vi bruge objekt orienteret databaser?

Database. lv/

MSE PRESENTATION 2. Presented by Srunokshi.Kaniyur.Prema. Neelakantan Major Professor Dr. Torben Amtoft

Database kursus Forår 2013

Arkitektur principper og design mønstre til realisering af enterprise applikationer baseret på rige domænemodeller (og.net)

IBM Network Station Manager. esuite 1.5 / NSM Integration. IBM Network Computer Division. tdc - 02/08/99 lotusnsm.prz Page 1

Database design for begyndere

ER-modellen. Databaser, efterår Troels Andreasen. Efterår 2002

Arkitektur for begyndere

Software Projekt NoSQL vs RMDB

Sporbarhed og Rapportering i Quality Center. Kim Stenbo Nielsen NNIT Application Management Services

Databasesystemer. Databaser, efterår Troels Andreasen. Efterår 2002

SOFTWARE PROCESSES. Dorte, Ida, Janne, Nikolaj, Alexander og Erla

Side 1. Databaser og SQL. Dagens gang. Databasebegreber. Introduktion til SQL Kap 1-5

Design by Contract. Design and Programming by Contract. Oversigt. Prædikater

Abstrakte datatyper C#-version

Design by Contract Bertrand Meyer Design and Programming by Contract. Oversigt. Prædikater

Data lagring. 2. iteration (implement backend)

Installation og Drift. Aplanner for Windows Systemer Version 8.15

Conceptual, logic, physical

Skriftlig opgave. Designtanker i database-nære systemer

Sammenligning af Objekt-orienteret databaser og Relationelle databaser.

METODER ARV KLASSER. Grundlæggende programmering Lektion 5

Help / Hjælp

Installation og Drift. Aplanner for Windows Systemer Version

Tietgenskolen - Nørrehus. Data warehouse. Database for udviklere. Thor Harloff Lynggaard DM08125

FKG datamodellen Version ArcGIS integration Sidste revisionsdato: 23. maj 2014

Det er muligt at chekce følgende opg. i CodeJudge: og

Dygtig.NET / C# udvikler med stor erfaring fra både offentlige organisationer og private virksomheder.

Forskellige databaser

Database programmerings tips

Digitaliseringsstyrelsen

3. SEMESTER 2. PROJECT MULB Gruppe september 2015

Ugeseddel 4 1. marts - 8. marts

Databaseadgang fra Java

STS Designdokument. STS Designdokument

Software Construction 1 semester (SWC) Spørgsmål 1

Formål I forbindelse med opgradering af Navision Stat fra NS til NS7.0 skal den tilhørende Navision Stat licens migreres til NAV2013R2.

FESD-standardiseringsgruppen Att: Palle Aagaard IT- og Telestyrelsen IT-strategisk kontor Holsteinsgade København Ø

Søren Løbner (lobner) ddb Databaser

A Profile for Safety Critical Java

Fart på SAP HANA. Sådan laver du analyser direkte på dine data i realtid. Copyright 2012 FUJITSU. Fujitsu IT Future, København, den 16.

PHP Quick Teknisk Ordbog

! Kia Dahlen. Kamilla Klein, Pia Jensen og Maria Korshøj Andersen.

Klasser og Objekter i Python. Uge 46 Learning Python: kap 15-16,

DSB s egen rejse med ny DSB App. Rubathas Thirumathyam Principal Architect Mobile

MetaService. Installations og burger guide.

Model Drevet Design i Praksis

Databasesystemer, forår 2005 IT Universitetet i København. Forelæsning 3: E-R modellering. 17. februar Forelæser: Rasmus Pagh

Listen over reserverede ord er meget lang, men de væsentligste vil jeg beskrive her i denne artikel:

IT-Basecamp Real World Java EE Patterns Adam Bien. Real World Java EE Patterns, Adam Bien Copyright Lund&Bendsen A/S

DOCUMENTATION FULLY DRESSED USE-CASE. 29. oktober 2012 [ TEMA PERSISTENS DOKUMENTATION] Use-case: Process Order

Indhold. Senest opdateret:03. september Side 1 af 8

Objects First with Java A Practical Introduction Using BlueJ

A11: Last Year s Exam

Version Dato Beskrivelse /11/2012 Initial version /03/2013 Tilføjet eksempel med Template Agent, generelt udvidet dokumentet.

Introduktion til SQL queries

De vigtigste SQL-sætninger. SQL kap Oprette database. DDL og DML

SWC eksamens-spørgsmål. Oversigt

PROJEKT 3. The Design Diaries. LINK TIL BLOG: Af Mikkel Borg Svendsen & Sebastian Frank MUL B

Singleton pattern i Java

ER-modellen. Databaser, efterår Troels Andreasen. Efterår 2002

Udvikling af DOTNET applikationer til MicroStation i C#

Backup Applikation. Microsoft Dynamics C5 Version Sikkerhedskopiering

OS2 Opgavefordeler. Løsningsbeskrivelse Version 2. Udarbejdet af Miracle A/S Simon Møgelvang Bang

Projekt: Database. Multimedia Design: Semester 3 - projekt 01. Sabine Larsen cph-sl176@cphbusiness.dk. Anastasia Keller cph-ak186@cphbusiness.

Introduktion til SQL

Terese B. Thomsen 1.semester Formidling, projektarbejde og webdesign ITU DMD d. 02/

VPN VEJLEDNING TIL MAC

! Kia Dahlen. Kamilla Klein, Pia Jensen og Maria Korshøj Andersen.

extreme Programming Kunders og udvikleres menneskerettigheder

DATABASE Projekt 1-3. semester

Øvelse 9. Klasser, objekter og sql-tabeller insert code here

SEPA Direct Debit. Mandat Vejledning Nets Lautrupbjerg 10 DK-2750 Ballerup

10. Rapporter i BBR... 2

Begrænsninger i SQL. Databaser, efterår Troels Andreasen

Import af rekursivt (parent-child) hierarki i Palo

CHAPTER 8: USING OBJECTS

Da beskrivelserne i danzig Profile Specification ikke er fuldt færdige, foreslås:

Dagens program. Domæner. change log- screen shots hver gang I har arbejdet med themet. Arkitekturen bag en wp blog. Hvad er widgets.

Basic statistics for experimental medical researchers

Vejledning til Teknisk opsætning

applikation----x----odbc driver manager----foobar ODBC driver----foobar database

Hvor er mine runde hjørner?

Indhold. Senest opdateret : 30. juli Side 1 af 5

Underbilag 2.24 Kommunernes it-miljø

Hassansalem.dk/delpin User: admin Pass: admin BACKEND

2013 SP1. Konfiguration af koncernindblik. Configuration Guide

Fra idé til virkelig med Azure Mobile Services

Foto-Applikation Dokumentation. Et Kod-i-Ferien projekt

CLR Integration. Af Torsten Holtse, pbs Indhold

UPLOAD. Af Database og Website til Skolens Server

DK - Quick Text Translation. HEYYER Net Promoter System Magento extension

Project Step 7. Behavioral modeling of a dual ported register set. 1/8/ L11 Project Step 5 Copyright Joanne DeGroat, ECE, OSU 1

Opsætning af MobilePBX med Kalenderdatabase

PARALLELIZATION OF ATTILA SIMULATOR WITH OPENMP MIGUEL ÁNGEL MARTÍNEZ DEL AMOR MINIPROJECT OF TDT24 NTNU

Transkript:

DATALOGISK INSTITUT DET NATURVIDENSKABELIGE FAKULTET AARHUS UNIVERSITET Hovedopgave Master i Informationsteknologi linien i Softwarekonstruktiona Object-Relational Mappers i.net af Jesper Veggerby 15. juni 2010 Jesper Veggerby, studerende Jørgen Lindskov Knudsen, vejleder Datalogisk Institut Aarhus Universitet Åbogade 34 8200 Århus N Tlf.: 89425600 Fax: 89425601 E-mail: cs@cs.au.dk http://www.cs.au.dk/da

Indholdsfortegnelse 1 English Summary... 4 2 Indledning... 5 2.1 Terminologi og Forkortelser... 5 2.2 Motivation... 6 2.3 Hypotese... 7 3 Impedence Mismatch... 8 3.1 Identitet... 9 3.2 Associationer og Aggregeringer... 9 3.3 Nedarvning... 11 3.3.1 Table per Hierarchy... 12 3.3.2 Table per Concrete Class... 13 3.3.3 Table per Class... 14 3.4 Encapsulation... 14 3.5 Polymorfisme... 15 4 Sammenligningsgrundlag... 15 4.1 Features... 15 4.2 Performance... 16 4.3 Implementation... 16 5 ORM Key Features... 16 5.1 Model First... 17 5.2 Schema First... 17 5.3 Code Only... 17 5.4 OO Konstruktioner... 18 5.4.1 Associationer... 18 5.4.2 Nedarvning... 18 5.5 Persistence Ignorance... 18 5.6 Lazy Loading... 18 5.6.1 SELECT N + 1... 19 5.6.2 Ghost Objects... 20 5.7 LINQ Support... 22 6 Udvalgte Mappers... 23 6.1 ADO.NET Entity Framework... 24 6.2 NHibernate... 24 6.3 LightSpeed... 24 7 Metode... 25 7.1 Features... 25 7.2 Performance og Implementation... 25 7.3 Test Cases... 29 Side 1 af 67

8 ADO.NET Entity Framework... 29 8.1 Feature Evaluering... 29 8.2 Performance... 30 8.2.1 Load by id... 30 8.3 Implementation... 31 8.3.1 Mapning... 31 8.3.2 Refactoring... 36 8.3.3 Learning Curve, Dokumentation og Community... 36 9 NHibernate... 37 9.1 Feature Evaluering... 37 9.2 Performance... 38 9.2.1 SessionFactory... 38 9.2.2 NHibernate og LINQ... 38 9.2.3 Ghost Objects... 40 9.3 Implementation... 40 9.3.1 Mapning... 40 9.3.2 Querying... 41 9.3.3 One-Many inserts... 43 9.3.4 Learning Curve, Dokumentation og Community... 43 10 LightSpeed... 44 10.1 Feature Evaluering... 44 10.2 Performance... 45 10.2.1 Eager Loading... 45 10.2.2 LINQ... 46 10.3 Implementation... 47 10.3.1 Mapning... 47 10.3.2 Eager loading... 49 10.3.3 Learning Curve, Dokumentation og Community... 49 11 Sammenfatning... 50 12 Alternativer... 51 13 Konklusion... 53 14 Referencer... 55 15 Figurer... 60 16 Appendix A Gængse RDBMS... 61 17 Appendix B Downloads... 62 18 Appendix C ORM 3rd Party Tools... 62 19 Appendix D Test Case definitioner... 63 Side 2 af 67

Side 3 af 67

1 English Summary Throughout history relational databases have been widely used and are based on a well-known and proven technology. Developers have long used relational databases as a mean to persist and query data. With the adoption of the object-oriented programming paradigm, the relational model has followed along, although there are fundamental conceptual differences between the two paradigms. Object-Relational Mappers are applied as a technique that generically overcomes these differences or at least remedies them, by mapping the classes in the object oriented system to the table in the database. There exist numerous ORM frameworks and choosing the right framework to use in a project or organization, based on needs and requirements can be difficult in this large market. The purpose of this work is to determine how the most popular ORM frameworks differ, and if it is possible to categorize a specific ORM to allow a qualified selection of the right ORM for a specific project or organization. This work outlines key features that define an ORM. These key features are evaluated against three popular.net based ORM frameworks (Entity Framework, NHibernate and LightSpeed). Furthermore a sample mapping for all three using a domain model of a simplified e-commerce system is subjected to testing. The conclusion of this work is that the three tested ORM frameworks have (almost) all the key features. The main finding though is that it is possible to categorize the tested ORM frameworks based upon the focus of the usage. In short the findings are: NHibernate is the most decoupled and flexible solution. Entity Framework is the simplest to develop for. LightSpeed has some unique features that make it a niche player in the market. Performance differences are negligible. Side 4 af 67

2 Indledning Den relationelle model som grundlag for databaser blev introduceret i 1969 (af E.F. Codd), i løbet af 1970 ere arbejde IBM på et database system baseret på Codd s model. Deres første prototyper var tilgængelige i 74/75 og i 78/79 var havde de tilføjet et strukturered query sprog, SQL. IBM s database system startede under navnet System R, gik i produktion under navnet SQL/DS og blev senere til Database 2 (DB2) som eksisterer den dag i dag. Relationelle databaser er blevet den mest udbredte database teknologi. Objekt-orienteret programmering (OOP) startede med spæde skridt i form af objekter i programmering allerede i sproget Simula 67 i 1960 erne. OOP blev til et begrem med Smalltalk i 70 erne, og har i løbet af 1990 erne vundet indpas som det dominerede paradigme i programmeringssprog, eksempler på dette er Java, C#, C++, Ruby, Python, etc. Sammen med OOP s indpas og relationelle databasers generelle udbredelse, har det været nærliggende at benytte disse databaser som persistens i OOP systemer. I de følgende kapitler analyseres de problemstillinger der ligger i den grundlæggende forskel mellem disse to paradigmer. De eksisterende løsninger beskrives og evalueres og alternative løsninger vil blive berørt. 2.1 Terminologi og Forkortelser I det følgende vil der blive benyttet disse forkortelser og termer: OOP OODBMS RDBMS RM ORM EF, EF4 L2S NH LS NoSQL Object-Oriented Programming Object-Oriented Database Management System Relational Database Management System Relational Model Object/Relational Mapping eller Object/Relational Mapper ADO.NET Entity Framework og EF version 4 (inkl. i.net 4.0) LINQ to SQL NHibernate LightSpeed En bevægelse der promoverer løsninger der ikke er Side 5 af 67

LSP SQL baseret på relationelle databaser Liskov Substitution Principle Structured Query Language Generelt vil der blive brugt danske udtryk, med mindre den engelske pendant bliver brugt de-facto i det danske fagsprog. Referencer til entiteter, tabeller, klasser, properties, etc. er markeret med fed skrift, kode snippet eller blokke er markeret med Courier New font. 2.2 Motivation Et program skrevet i et OOP-sprog beskriver et objekt system, der indeholder både tilstand (state) og opførsel (behaviour). Dette objekt-system udgør den eksekverbare del af programmet. En udviklingsmetode der benytter OOP til er Object Oriented Analysis & Design (OOA&D) (1). I OOA&D modelleres det domæne programmet håndterer (fx. Ordrer, Ordre-linier, Produkter, Kunder, etc. for et ecommerce system) i en domæne model/domain Model. Under afvikling af programmet instantieres og manipuleres objekter i hukommelsen. Når programmet afsluttes vil disse objekter og deres tilstand forsvinde. For transiente objekter der kun eksisterer for at afvikle selve programmet, eg. elementer i selve brugergrænsefladen, er dette direkte ønsket, da ressourcer dermed bliver frigivet. Andre objekter skal kunne persisteres og være tilgængelig ved næste program afvikling, eg. objekterne i domæne modellen. For eksempel for ecommerce systemet skal ordrer persisteres til næste afvikling af programmet. Det kan også være at objekterne skal deles mellem forskellige programmer, eg. selve ordremodtagelsen, ordre behandlingen og fakturering kunne være 3 forskellige programmer. Der er flere forskellige måder at håndtere objekt persistens på, for eksempel: Serialisering Objekt Orienterede Databaser (OODBMS) Relationelle Databaser (RDBMS) Serialisering og OODBMS vil ikke blive berørt nærmere, da disse historisk set har opnået moderat adoption som generiske persistensmekanismer. Side 6 af 67

Relationelle Databaser har historisk set været en meget anvendt metode til at håndtere data på. Med modne systemer fra de allerstørste software leverandører på markedet, Oracle, Microsoft, IBM, Sun, etc., samt indtil flere Open Source alternativer, og versioner til alle platforme fra embeddede over PC til server baserede løsninger har relationelle databaser en udbredelse der gør dem til en persistens mekanisme der ikke kan ses bort fra. Mange virksomheder har derudover investeret betragtelige summer i store relationelle database infrastrukturer. Med struktureret programmering faldt valget at relationelle databaser meget naturligt, hvor de problematikker der er ifht. OOP ikke fandtes. Database kald blev udført med indlejrede SQL kald, bedst eksemplificeret via embedded SQL i COBOL (2). Resultaterne blev håndteret for det det var: data. Med paradigme skiftet fra struktureret programmering til objekt orienteret programmering, er den relationelle databases udbredelse fulgt med, som den mest almindelige metode til at persistere objekter på - selvom den relationelle model vs. OOP har visse problemstillinger (som uddybes senere). Hertil findes der på markedet mange løsninger til at håndtere persistens af objekter og afhjælpe, abstrahere eller i hvert fald minimere de konsekvenser den fundamentale forskel der er på de to paradigmer har. Disse kendes under ét som Object-Relational Mappers (O/RM eller ORM). Der evalueres på ORM s til Microsofts.NET framework, da dette har primær fokus i den organisation, jeg pt. er ansat i. I den seneste tid har der været et voksende community for brug af databaser der ikke er baseret på en relationel model, en "bevægelse" der går under navnet NoSQL. NoSQL er en samling af forskellige approaches til persistens, og blandt nogle af dem som benytter NoSQL kan nævnes Google, Amazon, Twitter og Facebook. 2.3 Hypotese I al sin enkelhed går ORM ud på at persistere objekters tilstand (state) i en relationel database (RDBMS). Dette opnås ved at der defineres en mapning imellem tabeller og kolonner fra den relationelle model til klasser og properties i OOP modellen. Side 7 af 67

Der findes mange O/R Mappers (ORM) i.net verdenen (3), både kommercielle og Open-Source. For hver eneste ORM, findes der en mere eller mindre seriøs holdning til hvad styrker og svagheder er ved alle de andre, og ikke mindst hvorfor lige netop den selv er den helt rigtige, se Figur 1 (4). Hvordan adskiller de mest populære ORMs sig fra hinanden? Og hvilke parametre kan man opstille så man kan kvalificere valget af en ORM at basere sit projekt på? Figur 1 How Fanboys See.NET Data Access Strategies 3 Impedence Mismatch Der er som nævnt nogle helt fundamentale forskelle imellem den relationelle model og den objekt orienterede, som en ORM skal kunne løse eller i hvert fald håndtere. Side 8 af 67

Overordnet set er der den basale forskel i hvordan de to paradigmer er opstået: The object-oriented paradigm is based on proven software engineering principles. The relational paradigm, however, is based on proven mathematical principles. (5) 3.1 Identitet I OOP taler man om at objekter har "identitet", i.e. et objekt repræsenterer en selvstændig entitet, det adskiller sig fra alle andre objekter. At et objekt har identitet er noget der er implicit i objekt systemet, eg. objektets tilstedeværelse i hukommelsen repræsenterer dets identitet. I den relationelle database optræder identiteter ved hjælp af database nøgler (primary keys) og er repræsenteret eg. vha. et unikt tal (i en given tabel angiver id = 87 en specifik række). Oftest er en nøgle dog kun unik pr. tabel, i.e. tabel A kan have en række med id = 87, og det kan tabel B også - der findes alternativer, e.g. uniqueidentifier/guid (Global Unique Identifier) der kan sikre uniqueness på tværs af tabeller (endog uniqueness globalt, med så lille en sandsynlighed for kollision af dette er unikt i alle praktiske forhold (6)). Dette gør at man i objekt systemet skal tilknytte den relationelle models identitet som "faktisk" identitet for objektet. At den relationelle identitet og objektets identitet er uafhængige, kan ses ved at der kan eksistere to instanser af et objekt der repræsenterer den samme række/identitet fra databasen. En anden problemstilling med identitet er hvor og hvordan den relationelle identitet genereres. Idet objekterne (oftest) kreeres initielt i objekt systemet, er der ikke nogen kendskab til den identitet objektet vil have i databasen (som oftest vil denne først blive genereret når objektet persisteres i databasen), dvs. at selvom objektet har en identitet ifht. objekt systemet har det (endnu) ingen identitet ifht. databasen. Dette kan i praksis afhjælpes ved at benytte GUID som relationel identitet, da de med meget stor sandsynlighed kan genereres unikke i selve objekt systemet. 3.2 Associationer og Aggregeringer Affødt af problematikken omkring identitet er der også en fundamental forskel i hvordan de to paradigmer håndterer referencer (associationer og aggregeringer i OOP og relationer i RM). Idet en reference mellem 2 entiteter (det værende sig objekter eller rækker i databasen), så dannes disse imellem to identiteter, dvs. i Side 9 af 67

OOP er associationer og aggregeringer direkte imellem objekternes identitet, e.g objekt A refererer objekt B. I RM er det imellem rækkernes keys (foreign keys), eg. række A med id A' refererer B' der er id på række B. En anden problematik kommer ifht. kardinalitet af relationer. Ægte one-one relationer kan kun modelleres i en relationel database, ved at de to tabeller har den samme primary key (Figur 2). A B PK,FK1 B' PK B' Figur 2 One-one relation via delt primary key En anden metode er at er at benytte en standard one-many type relation, ie. i en tabel A med kolonne B der er foreign key til tabellen B, og tilføje et unikt index på B kolonen i A (Figur 3). A B PK A' PK B' FK1,U1 B' Figur 3 One-one relation via unique constraint/index Many-many relationer modelleres vha en såkaldt link table (junction table, join table, association table, etc. (7)), (Figur 4). PK A A' AB PK,FK1 PK,FK2 A' B' PK B B' Figur 4 Many-many relation med link table Side 10 af 67

Denne konstruktion er som sådan ikke en egenskab ved Tabel A eller B, men blot en liste over rækker i A og B der er knyttet logisk sammen (relateret) det kan i princippet fortolkes som to one-many relationer fra en virtuel entitet AB. I et objekt system er det derimod objekterne A og B der refererer flere elementer af den anden klasse, ie. A har reference til flere B og B har reference til flere A, dvs. en link tabel eller klasse er ikke påkrævet. Konstruktionen i Figur 4 supporterer kun at A og B kan have én fælles reference, i.e. A og B kan kun være knyttet sammen én gang (idet foreign keys i link tabellen samtidig udgør primary key). Hvis det er nødvendigt at kunne have flere relationer imellem samme objekter kan dette gøres ved at have en explicit primary key (se Figur 5), men så er man muligvis ude i en situation hvor relationen i sig selv har en identitet (ie. hvilken af relationerne mellem A og B menes der?) hvor det kan være fornuftigt (hvis ikke påkrævet) at link tabellen har egen repræsentation i objekt systemet. PK A A' AB PK Id FK1 A' FK2 B' PK B B' Figur 5 Many-many relation med explicit primary key 3.3 Nedarvning OOP har konceptet omkring nedarvning, hvilket ikke findes i den relationelle model. For at supportere persistens af nedarvede objekter skal der defineres en strategi for hvordan dette kan oversættes til den relationelle model. Der er 3 strategier med hver deres fordele og ulemper (5). Et nedarvningshierarki er ikke begrænset til at skulle bruge én af disse, men kan kombinere dem på den måde der er mest hensigtsmæssig ifht. den konkrete situation. Disse vil blive uddybet i det følgende, eksemplificeret ved det simple nedarvningshierarki vist i Figur 6. Side 11 af 67

+Name +SKU Product Book +Author +ISBN +Size +Color Shoe Figur 6 Simpelt nedarvnings hierarki 3.3.1 Table per Hierarchy Alle properties i alle subklasser gemmes i én tabel (Figur 7). Product PK Id SKU Name Book_Author Book_ISBN Shoe_Size Shoe_Color Figur 7 Table per Hierarchy Oftest benyttes en "discriminator column" til at afgøre hvilken klasse der rent faktisk er tilfældet, eg. Type der kan have værdierne "Book" og "Shoe" eller 1 og 2. Fordele: Simpel struktur Simple queries til at afgøre hvilken subklasse et givent Product har. Ulemper: Ikke optimalt ved store nedarvningshierarkier pga. antallet af kolonner Side 12 af 67

Potentielt meget spildplads (specielt hvis subklasser har mange properties), pga. mange NULLABLE kolonner Udover den øverste superklasse kan der ikke benyttes constraints på kolonner (eg. der kan ikke specificeres en NOT-NULL constraint, eller der skal defineres en mere kompliceret constraint). 3.3.2 Table per Concrete Class Hver klasse med samtlige properties (ie. også superklassers) gemmes i hver sin tabel (Figur 8). Product PK Id SKU Name Book Shoe PK Id PK Id SKU Name Author ISBN SKU Name Size Color Figur 8 Table per Concrete Class Fordele: Kan understøtte relativt store nedarvningshierarkier (specielt hvis de er flade) Simpelt at finde alle objekter af en given klasse Ulemper: Primary keys fragmenteret/splittet over flere tabeller UNION operationer uundgåelig for selv simple queries Tabel skemaerne skal holdes in-sync, ie. SKU i Product, Book og Shoe skal (bør) have samme definition Side 13 af 67

SELECT statements vil være ineffektive, eg. et load af alle produkter vil give samme situation med kolonner som i "Table per Hierarchy" (i.e. alle kolonner skal repræsenteres), eller der skal eksekveres en query pr. tabel. 3.3.3 Table per Class Hver subklasse's explicit definerede properties gemmes i en tabel med foreign key til superklassen s tabel (Figur 9). Product PK Id SKU Name Book Shoe PK,FK1 Id PK,FK1 Id Author ISBN Size Color Figur 9 Table per Class Fordele: Supporterer i princippet uendeligt store nedarvningshierarkier. Ulemper: Specielt INSERT operationer er komplicerede da der skal oprettes foreign keys til "hoved tabellen". JOIN operationer er uundgåelige for selv simple queries. 3.4 Encapsulation I OOP er selve implementation (behavior) og tilstand (state) indkapslet i et objekt og er kun tilgængeligt on a need-to-know-basis. Det vil sige en klasse specificerer hvilket metoder og properties der kan tilgåes fra andre objekter (via access modifiers, eg. private, protected, internal, internal protected og public). Side 14 af 67

Den relationelle model derimod supporterer kun tilstand (data) og interfacet er principelt public (hvis man ser bort fra at diverse RDBMS løsninger supporter adgangsstyring på forskellige niveauer, så er det ikke en integreret del af den relationelle model). 3.5 Polymorfisme Polymorfisme ( evnen til at antage mange skikkelser ) i OOP betyder at en nedarvet klasse B kan erstatte/overskrive funktionalitet X() fra en superklasse A. Dvs. B.X() er logisk forskellig fra A.X() omend kompatibelt i den forstand at funktionaliteten har samme signatur. Idet B is-a A, kan man i alle variable, metoder, etc. der refererer A benytte et objekt af klassen B, men funktionaliteten X() følger objektet. Dvs. i peudo-kode: A a = new A(); a.x(); // kalder A.X() a = new B(); a.x(); // kalder B.X() Da polymorfisme hænger meget sammen med nedarvning og behavior, er dette koncept ved OOP heller ikke supporteret i RM. 4 Sammenligningsgrundlag Der vil i de efterfølgende kapitler blive foretaget en empirisk undersøgelse og sammenligning af de nævnte udvalgte ORMs på baggrund af følgende kriterier: 4.1 Features Hvilke af følgende features supporteres af de enkelte ORM, og hvorledes implementeres det? Model first se 5.1 nedenfor Schema first se 5.2 nedenfor Code only se 5.3 nedenfor OO konstruktioner o Associationer One-one Many-one Many-many o Nedarvning se 3.3 ovenfor Side 15 af 67

Table-per-hierarchy Table-per-concrete class Table-per-class Mix af disse Persistence Ignorance/Supporterede RDBMS se 5.5 below Lazy-loading se 0 nedenfor LINQ Support se 5.7 nedenfor 4.2 Performance Hvordan oversættes navigering af objekt modellen til SQL kald til databasen? Kvalitativ analyse af genreret SQL Select N+1 se 0 nedenfor 4.3 Implementation Hvilken impact har det at bruge ORM en på udviklingsprocessen/-projektet? Mapping o Hvordan? o Refactoring 1 Learning curve o Getting Started Guides o Dokumentation Scope Kvalitet o Community Tooling & Extensions o Mapnings værktøjer (designere) o 3rd party add-ons 5 ORM Key Features Herunder følger en uddybning af nogle af de beskrevne features i 4.1 ovenfor. 1 Som defineret på eg. Wikipedia Code refactoring is the process of changing a computer program's source code without modifying its external functional behavior in order to improve some of the nonfunctional attributes of the software. (38) Side 16 af 67

5.1 Model First Ved "Model First" forstås den tilgang til ORM hvor der først laves en objekt model og derefter mappes denne til et database skema. Fordelene ved denne tilgang er at det er selve objekt-modellen der er i fokus. Denne metode er derfor specielt velegnet til OOA/D baserede projekter, hvor Domæne Modellen er central. "Model First" ORMs bruger ofte forskellige former for design værktøjer til at modellere objekt/domæne modellen og kan i mange tilfælde også generere et database skema udfra mapningen (dvs. inkl. field definitioner, primary og foreign keys, constraints, etc.) 5.2 Schema First I "Schema First" tilgangen er databasen eller database skemaet tilgængeligt og denne mappes så til en objekt model. Denne metode er specielt velegnet til at bygge nye UI's (User Interfaces) på en eksisterende database. Dette kan være specielt nyttigt hvis der er tale om en (stor) eksisterende database og/eller en database der er optimeret ifht. et specifikt brug. "Schema First" fordrer enten at man tilpasser sin Domæne Model til databasen, eg. Active Record (8), eller at den benyttede ORM har tilpas fleksibilitet til at kunne mappe database skemaet ind i den ønskede domæne model. 5.3 Code Only En pendant til "Model First" er "Code Only", hvor man betragter sin domæne model som værende 100% separat fra sin ORM, e.g. klasserne skrives manuelt eller designes/genereres dynamisk udfra et UML klasse diagram i.e. POCO 2 klasser. "Code Only" tilgangen stiller det krav til ORM'en at det kan operere på objekter uden at have kode afhængighed, eg. ved at kræve nedarvning fra en specifik baseclass, her til, hvilket kræver specielle forhold eg. ifht. lazy-loading og indkapsling. 2 Plain Old CLR Objects, et pun på pendanten i Java POJO (Plain Old Java Objects). Betydningen er at det handler om simple objekter der ikke har nogen afhængigeder til andre frameworks eller lignende, eg. via attributter, nedarvning eller code-mæssigt (17) Side 17 af 67

5.4 OO Konstruktioner 5.4.1 Associationer Supporteres many-many relationer uden at skulle mappe link tabellen til en klasse 3, se Figur 4. 5.4.2 Nedarvning Hvilke typer (se 3.3 ovenfor) af nedarvnings mapning supporteres, 5.5 Persistence Ignorance En (afledt) fordel ved at bruge en ORM er at man ofte vil blive RDBMS "agnostic"/uafhængig (persistence ignorance), i og med at håndteringen af persistens og querying foretages af ORM, kan database integrationen abstraheres væk i ORM en. Dette betyder an en given ORM oftest vil kunne understøtte flere forskellige typer RDBMS, eg. både server baserede (som Oracle, MySQL og MS SQL) og/eller embeddede (som SQLite eller MS SQL CE). 5.6 Lazy Loading Lazy-loading er den funktionalitet at et associeret (om det er del af en 1:1, 1:n eller n:n association er irrelevant) objekt ikke loades i samme query som parent objektet. Vi betragter klassediagrammet i Figur 10. Order +Number +Order 1 +Lines * OrderLine +Quantity -Lines * +Product 1 Product +Name +ListPrice +SKU Figur 10 Lazy-loading eksempel klasse diagram 3 Dette er for eksempel nødvendigt i Linq to SQL. Side 18 af 67

Hvis et givet Order objekt loades vil de relaterede OrderLine's ved lazy-loading først blive hentet (e.g. SELECT * FROM OrderLine WHERE OrderNumber = @Number) når denne property navigeres. Ligeledes med OrderLine -> Product. Dette betyder at der kun bliver loadet det (og dermed udført de SQL statements) der er nødvendige. 5.6.1 SELECT N + 1 En ulempe ved lazy-loading er at det kræver at brugeren af ORM'en skal være opmærksom på brugen af associationer, ellers er det meget let at lave såkaldte SELECT N+1 situationer (9). En SELECT N + 1 situation er meget almindelig, i situationer hvor man har en serie af objekter der har en 1:1 (eller anden kardinalitet, men det ses typisk ved 1:1) relation til et andet objekt. For eksempel i e-handels systemer hvor en ordre, har en række ordre-linier der hver gælder for ét givet produkt. Hvis vi i vores program skal lave en ordre præsentation, der viser ordre header, ordre-linier og detaljer om produkterne herpå, kræver det naturligt at selve Ordre objektet loades. I vores brugergrænseflade skal derfor itereres over ordrelinier på ordren og vises eg. produkt navn og produkt SKU og bestilt antal. Idet der benyttes lazy-loading vil læsningen af Order.OrderLines property afføde et SELECT statement via ORM'en der loader alle OrdreLinier for den givne ordre. Antag at for en given Order er der N OrderLines. Når disse præsenteres i brugergrænsefladen vises produkt navnet, dette betyder at OrderLine.Product læses og igen afføder det via lazy-loading et SELECT statement imod databasen. Idet dette gøres for hver af de N ordre-linier vi har læst ind, eksekveres der N næsten ens SELECT statements imod databasen plus det SELECT statement der loadede alle OrderLines ind - heraf kommer navnet SELECT N + 1. SELECT N + 1 situationer kan for eksempel afhjælpes ved at pre-fetch informationer, fx. kunne ORM'en i ovenstående tilfælde instrueres i at loade det associerede Product sammen med en OrdreLinie. Side 19 af 67

5.6.2 Ghost Objects En anden problematik er en kombination af Ghost Objects og nedarvning ifht. Liskov' Substitution Principle (10), som kan opstå hvis man benytter en ORM der anvender Ghost Objects til at opnå lazy-loading (som eg. NHibernate gør). Ghost Objects er proxy objekter der genereres automatisk ved runtime for at opnå lazy loading. Dette bruges for eksempel til Code Only (se 5.3 ovenfor)/poco modeller hvor man for eksempel ikke har en base class der nedarves fra (som håndterer lazy-loading). Teknisk set er et Ghost Object en instans af subklasse til entitets klassen, illustreret i Figur 11. +Name +Age Person (Ghost) Person +Name +Age Figur 11 Ghost Objects Ghost objektet overrider properties og metoder fra base class (hvilket så stiller et explicit krav om at alt er martkere virtual, hvilket ikke er default i.net, i modsætning til eg. Java) og implementerer disse som lazy-loading (i.e. værdien loades først ved navigering af property, invokation af metode, etc.). En af fordelene ved Ghost Objects er at man kan navigere en lazy-loaded property og tilgå enkelte properties på denne, eg. primært Id, uden at der genereres et kald til databasen (Id på child objektet er ved et one-many relation kendt på load tidspunkt af parent objektet, da foreign key ligger på parent tabellen). Hvis man på child objektet tilgår en property der ikke er tilgængelig vil denne blive lazy loaded fra database. Det betyder eg.: var order = session.get<order>(id); // følgende vil ikke generere et kald til databasen da // CustomerId stammer fra Order tabellen Console.WriteLine(order.Customer.Id); Side 20 af 67

// name er ikke kendt, så her vil der blive foretaget et // kald til databasen og data vil blive hydreret ind i // order.customer Console.WriteLine(order.Customer.Name); Eksemplificeret vil man vha. Ghost Objects kunne få det virtuelle nedarvnings hierarki som vist i Figur 12. * +Super 1 SuperClass +SuperX +SuperY MainClass SubClassA +SubAX SubClassB +SubBX (Ghost) SuperClass +SuperX +SuperY (Ghost) SubClassA +SubAX (Ghost) SubClassB +SubBX Figur 12 Many-one relationer, ghost objects og nedarvning MainClass, SuperClass, SubClassA og SubClassB er klasserne fra vores domæne model. For hver af disse klasser som supporerer lazy-loading vil der blive oprettet et Ghost Object, eg. (Ghost) SubClassA eller (Ghost) SuperClass. (Ghost) SubClassA vil override alle properties i SubClassA til lazy-load varianter, det samme vil ske for SuperClass, men vil ikke være i samme gren af nedarvningshierarkiet. Dvs. SubClassA is-a SuperClass er sand Men SubClassA is-a (Ghost) SuperClass er falsk Side 21 af 67

Dette betyder at hvis vores model supporterer lazy-loading (MainClass har selvfølgelig også en Ghost, men denne er ikke vist i modellen) så vil load af MainClass betyde at vi laver et (pseudo-)select statement SELECT MainClassId, SuperClassId from MainClass. Med andre ord kender vi på initialiseringstidspunktet af MainClass kun Foreign Key på SuperClass tabellen. Dette er ikke nok til at afgøre hvilken reel klasse (SuperClass, SubClassA eller SubClassB) der reelt refereres (denne information ligger fx i en discriminator column på SuperClass tabel-per-hierarchy strukturen). Derfor vil MainClass.Super blive initialiseret med et (Ghost) SuperClass objekt. Derved får vi at vi ikke kan teste om MainClass.Super is-a SubClassA, på trods af at MainClass.Super rent faktisk kan referere til et validt SubClassA objekt. Dette overholder derfor ikke Lisskov s Substitutions Princip (10). What is wanted here is something like the following substitution property: If for each object o 1 of type S there is an object o 2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o 1 is substituted for o 2 then S is a subtype of T. 5.7 LINQ Support For netop.net baserede ORMs er det en ekstra feature at supportere LINQ (Language INtegrated Query (11)). LINQ blev introduceret i.net 3.5 og er en metode til at skrive queries direkte i managed kode. LINQ skal ikke forveksles med den metode SQL er embedded i e.g. COBOL (2), men er en abstraktion over (i princippet) mange forskellige underliggende query sprog. from person in persons where person.age > 37 select person.name Vil kunne alt efter hvad "persons" er (implementeret via IQueryable<T> interfacet) blive oversat til et SQL statement, en LDAP query, direkte evalueret i managed code imod objekter eller (som et tænkt eksempel) til udvælgelse af ens Friends på Facebook. Problematikken ved at skulle supportere LINQ i en ORM er oversættelsen fra managed code (via Expression Trees (12)) til det pågældende query sprog, eg. et Side 22 af 67

Criteria API, query sprog (eg. ESQL og HQL) eller direkte til en SQL dialekt (eg. T- SQL for MS SQL Server). For eksempel en relativt simpel LINQ query som følgende: from person in persons where person.birthday.day < 10 select person Er ikke helt så triviel i T-SQL: SELECT * FROM Persons WHERE DATEADD(dd, 0, DATEDIFF(dd, 0, Birthday)) < 10 Og da managed kode er en del mere ekspressivt end SQL kan man sagtens lave LINQ queries der overhovedet ikke kan oversættes til SQL. Dette betyder at de udviklere der skal benytte LINQ providerne er nødt til at have et vist kendskab til hvilke metoder/expressions den pågældende LINQ provider kan oversætte, eller ihvertfald bestræbe sig på kun at benytte et simpelt standard set af operationer, e.g. ==,!=, &&,, etc. Problematikken ifht. dette gøres ikke mindre af at evt. usupporterede expressions, først viser sig runtime, da det først er her de evalueres. Derudover er der problemstillinger hvis man laver en generisk applikation der er database agnostisk, så kan det være meget forskelligt hvad de enkelte providere supporterer. 6 Udvalgte Mappers Til Microsoft.NET frameworket findes en lang række ORM's, blandt andet: ADO.NET Entity Framework - Microsoft, incl. i.net 3.5 SP1 NHibernate open source (13) LightSpeed commercial (14) LLBLGen Pro commercial (15) Castle ActiveRecord open source (16), bygger oven på NHibernate og benytter Active Record design pattern (8) DataObjects.NET commercial (17) SubSonic open source (18) Side 23 af 67

LINQ to SQL Microsoft, incl. i.net 3.5 og frem og mangle flere (3) Der vil i det følgende blive kigget nærmere på 3 af disse, navnligt ADO.NET Entity Framework, NHibernate og LightSpeed. Baggrunden for at vælge disse 3 uddybes herunder. 6.1 ADO.NET Entity Framework I.NET 3.5 introducerede Microsoft LINQ to SQL (L2S) som en persistens teknologi til frameworket der bygget på det introducerede LINQ (Language INtegrated Query) concept. LINQ to SQL, havde den fordel at det var meget simpelt, men samtidig havde det også den ulempe at det var meget simpelt, man kunne fx. ikke modellere nedarvning, n:n relationer uden at skulle inkludere en klasse til link tabellen (7). I.NET 3.5 SP1 introducerede Microsoft ADO.NET Entity Framework (EF) som et reelt ORM og satte samtidig L2S i en reel "deprecated" tilstand (19). Med det netop (2010-04-12 (20)) frigivne.net 4.0 er næste version af EF frigivet (EF4), som indeholder flere features, som bringer den mere på højde med allerede etablerede ORM. EF er naturligt inkluderet da det er frameworkets eget svar på ORM. Der kigges på version 4 som er frigivet med.net 4.0. 6.2 NHibernate Oprindeligt baseret på Hibernate til Java, der begyndte tilbage i 2001. Hibernate blev ported til NHibernate, og den dag i dag forsøges stadig at holde kodebaserne feature kompatible således at NHibernate bygger på Hibernate erfaringer og vice versa. Første stable release af NHibernate kom i 2005 Både Hibernate og NHibernate er open-source og har et meget stort community. Dette sammen med historikken gør at NHibernate ligeledes er et helt oplagt valg at kigge på. Der kigges på version 2.1.2. 6.3 LightSpeed LightSpeed vælges som det kommercielle alternativ til open-source løsningen og Microsoft s egen. Side 24 af 67

Derudover er LightSpeed valgt pga. det slår sig op med nedenstående key features Small & Lightning Fast Designed for Testability Convention over Configuration Kilde: http://www.mindscape.co.nz/products/lightspeed/default.aspx En alternativ løsning der principelt ligeså godt kunne være valgt var LLBLGen Pro som er en ORM der har udviklet sig fra at være simpelt DAL code generering (LLBLGen) til en reel ORM i 2003. LightSpeed er en rimelig ny ORM, med 1. release i 2007, men har siden da gennemgået 3 major versioner, så den p.t. er på verion 3.1 (pr. 12. juni 2010). Der kigges på version 3.1. 7 Metode 7.1 Features På baggrund af dokumentation og andre kilder, evalueres og konsolideres features for de enkelte ORM s, jf. 4.1 ovenfor i et skema, om det er supporteret/muligt og under hvilke forudsætninger. 7.2 Performance og Implementation Performance og Implementation evalueres ved en (empirisk) undersøgelse. Til brug i den empiriske undersøgelse af de udvalgte ORM s benyttes flg. domænemodel der modellerer et meget simpelt e-commerce system, som vist i Figur 13. Side 25 af 67

Address +Street +PostalCode * Order +Orders +Order 1 +Lines * OrderLine +Quantity +GetPrice() * -Lines 1 +Address 1 +Customer 1 +Product -Customer 1 Customer +Name +Address Product +Name +ListPrice +SKU * +Products VipCustomer +DiscountPercentage Wholesaler +MinimumOrderQuantity 1 * +Categories Category +Name +Parent +SubCategories * Figur 13 Klasse diagram for domæne model til empirisk undersøgelse Modellen repræsenterer ikke best-practice hverken ifht. et e-commerce system eller principper for OOP generelt. For eksempel vil man næppe modellere forskellige kundetyper ved nedarvning i.e. nedarvning er en statisk konstruktion, så en basis kunde kan ikke (teoretisk set) skifte til at blive en VIP kunde, og en Wholesaler kan heller ikke samtidig være VIP. Denne konstruktion kunne for eksempel med fordel modelleres vha. et Role Pattern (21). Til dette behov opfylder modellen dog flg. behov, ifht. hvad der ønskes belyst: 1) Identitet fx. at det er det samme produkt (objekt!) der fås via OrderLine.Product som ved Category.Products 2) One-one relation (Customer <-> Address) 3) One-many relationer (Order <-> OrderLine og Category <-> Category - Category.SubCategories) 4) Many-many relation (Product <-> Category) 5) Nedarvning (Customer -> VipCustomer + Wholesaler) Side 26 af 67

a. Herunder de forskellige tilgange til nedarvnings mapning disse evalueres separat. 6) Simpel recursive reference (Category.Parent/Category.SubCategories) 7) SELECT N+1 kan testes ved for en given Order at liste de Products der er bestilt på denne 8) Ghost-problematikken kan testes ved Order.Customer 9) Lazy-loading vs. Eager loading for associationer NB. Product.Lines er bevidst gjort private for at udstille nogle problemstillinger. Databasen vil være en Microsoft SQL (Express) 2005 Server 4 som kører lokalt for at udelukke påvirkninger fra netværk. Implementationen vil foregå via (unit) test cases i Visual Studio 2010 (ikke Express da denne ikke indeholder unit test) og data vil blive opsamlet via output fra unit tests, SQL Profiler og for EF og NH via Entity Framework Profiler (22) hhv. NHibernate Profiler (23) de opstillede test cases og metodikken hertil er på ingen måder et udtryk for en best-practice brug af unit testing (24), det er udelukkende brugt som et pragmatisk værktøj til at eksekvere de ønskede teste 5. Selve mapningen laves med udgangspunkt i at databasen eksisterer, således at opgaven består i at mappe et eksisterende database skema ind i vores domæne model (Schema First, 5.2). Database skemaet/diagrammet er illustreret i Figur 14. 4 Kan hentes gratis fra http://www.microsoft.com/sqlserver/2005/en/us/express.aspx alternativt SQL Express 2008 http://www.microsoft.com/sqlserver/2008/en/us/express.aspx 5 For eksempel er det ved at bruge unit testing til dette formål, muligt kun at afvikle udvalgte tests fra et givet scenarie Side 27 af 67

Customer PK Id FK1,U1 Name Type VIP_Discount WS_MinOrderSize AddressId PK Address Id Street PostalCode PK FK1 Order Id CustomerId PK Product Id Name Price SKU PK FK1 Category Id Name ParentCategoryId OrderLine ProductCategory PK FK1 FK2 Id OrderId ProductId Quantity PK,FK2 PK,FK1 ProductId CategoryId Figur 14 Database diagram for empirisk undersøgelse Hvor Customer hierarkiet her er modelleret som et table-per-hierarchy, Type kolonnen benyttes som discriminator kolonne, diskriminator værdier ses herunder. ProductCategory er many-to-many link tabellen imellem Product og Category. Discriminator værdi (Type) Class 0 Customer (base class, standard kunde) 1 VipCustomer 2 Wholesaler Databasen vil være præ-populeret med et simpelt dataset, en ORM test vil altid blive udført på en ny oprettet og ny initialiseret database. Al source code og output fra test resultater er tilgængelig i medfølgende.zip fil. Side 28 af 67

7.3 Test Cases Alle tests findes i projektet MIS.Tests i VS2010 solution en som er tilgængelig via førnævnte URL. For at sikre at de samme tests bliver udfør på alle 3 ORM er defineres disse via interfaces, som unit test ene for de enkelte ORM er implementerer. Dette sikrer samtidig at der er sammenfald mellem test navnene på tværs af tests. Formål og beskrivelse er defineret via XML documentation på interface ene, disse interface er inkluderet i Appendix D Test Case definitioner. 8 ADO.NET Entity Framework 8.1 Feature Evaluering Features evalueres ved hjælp af dokumentation (25) for EF og implementationen: Feature Supporteret? Kommentar Model first Ja Add > Empty Model Schema first Ja Add > Generate from Database Code only Ja Det er muligt at bruge en eksisterende POCO model (26), men selve mapning kan ikke foretages via code (fjernet efter CTP3 release, og ikke inkluderet i RTW af.net 4 (27)), dette skal stadig gøres via Entity Modellen. One-one assoc. Ja One-one supporteres kun med tabeller der deler primary key One-many assoc. Ja Many-many assoc. Ja Dog ikke med explicit primary key på link tabellen Table-per-hierarchy Ja (28) (29) Table-per-concrete-class Ja (28) (30) Kaldes Table-per-concrete-type i EF. Er ikke supporteret af designeren, kræver redigering direkte i EDMX filen Table-per-class Ja (28) (31) Kaldes Table-per-type i EF Side 29 af 67

Mix nedarvings mapning Uvist 6 Persistence Ja Ignorance/Supporterede RDBMS MS SQL (32) native og 3rd party DB2, FireBird, Informix, MySQL, Oracle, PostgreSQL, SQLite, Sybase (33) Lazy-loading Ja Via en inherited baseclass (alle entiteter nedarver fra EntityObject), eller for POCO via Proxies (Ghost objects) LINQ Support Ja 8.2 Performance Entity Framework udstiller ikke nogen interface eller metoder der gør det muligt at opsamle de SQL kald der foretages af frameworket. Til dette skal derfor bruges enten SQL Profiler for at se hvilke queries der bliver eksekveret på en specific database eller via Entity Framework Profiler (22) hvor den sidstnævnte giver det bedst overblik over hvad der eksekveres hvornår. 8.2.1 Load by id Entity Framework udskiller sig fra de to andre testede ORMs ved ikke at have en explicit måde at loade et objekt ind fra databasen udfra en given primary key. Dette kan for eksempel gøres vha. Context.Product.Single(p => p.id == 1) Der giver flg. SQL statement: SELECT TOP (2) [Extent1].[Id] AS [Id], [Extent1].[Name] AS [Name], [Extent1].[Price] AS [Price] FROM [dbo].[product] AS [Extent1] WHERE 1 = [Extent1].[Id] Single skal, som navnet antyder, returnere præcis én entity, hvis query returnerer flere eller hvis der ikke returneres nogen entities, kastes en exception. Derfor inkluderes TOP (2) for at sikre at hvis der kommer mere end ét element 6 Det er ingen problem at modellere mixede nedarvningshierarkier i EF designeren, men der er ikke fundet dokumentation for at de kan lade sig gøre og det er heller ikke lykkedes at designe en model der kan kompilere. Side 30 af 67

(minimum 2) så kan dette detekteres. I dette tilfælde er dette overflødigt da Id er primary key for tabellen, og der kan dermed kun returneres max én række. 8.3 Implementation 8.3.1 Mapning Selve mapningen i EF foregår via en designer indbygget i Visual Studio. Mapningen foregår i en Entity Model (EM) og der benyttes begreber som Conceptual Model (CM) og Storage Model (SM). CM er objekt/domæne-modellen som man vil modellere ud fra SM der er den relationelle model i databasen. EM består derfor af CM, SM og en mapning mellem CM & SM. Dette gemmes i en XML fil,.edmx. På baggrund af Entity Modellen i EDMX filen kode genereres domæne modellen til C# klasser. Klasserne der genereres er pr. default defineret som public partial, dvs. det er muligt at lægge logik på klasserne, eg.: public partial class OrderLine { public double GetPrice() { return this.quantity * this.product.price * (this.order.customer is VipCustomer? (this.order.customer as VipCustomer).DiscountPercentage / 100 : 1); } } Designeren er meget intuitiv, og forudsætter et begrænset kendskab til koncepterne indenfor ORM, men som med alle 3 løsningner, hvis der er tale om meget mere end Active Record brug (som man reelt set kan opnå ved at bruge fx. LINQ to SQL) så fordrer det et større kendskab til problemstillingerne og løsningerne herpå, eg. nedarvning. 8.3.1.1 Many-many relationer Hvis man (som i 3.2 ovenfor) har en many-many relation der kan indeholde flere reference mellem de samme to entiteter, vil EF pr. default generere en ekstra entitet til associationen. Som nævnt i 3.2 er man muligvis i en situation hvor dette reelt er det man har brug for (i.e. relationen har en identitet). Side 31 af 67

Figur 15 Default many-many relation med explicit primary key i EF EF supporterer ikke at denne property ikke mappes. Ie. hvis PersonRole entiteten fjernes og erstattes af en Person <-> Role many-many relation der benytter PersonRole tabellen som link table fåes flg. fejl: Error 3025: Problem in mapping fragments starting at line 113: Must specify mapping for all key properties (PersonRole.Id) of table PersonRole. Hvilket netop henviser til at relationen har identitet og derfor bør EF kende den. 8.3.1.2 Schema First Ved denne metode auto-genereres Entity modellen automatisk på baggrund af et database skema. For eksempel vil database skematet der benyttes i implementations testen (se Figur 14 i 7.2 ovenfor) give en autogenereret Entity Model som vist i Figur 16. Side 32 af 67

Figur 16 Entity Model "Generate from Database" De eneste forskelle fra denne til den designede domain model er: 1) Navnene på Category.Parent/Category.SubCategories (disse navne er heller ikke angivet noget sted i database skemaet). 2) Customer er ikke et nedarvnigshierarki, men da det er en konstruktion der ikke er supporteret i den relationelle model, kan dette ikke modelleres i databasen og dermed kan designeren heller ikke genkende denne. 3) Address -> Customer er mappet som en one-many relation 4) Product.Lines er ikke private, men dette kan ikke modelleres i databasen Side 33 af 67

Hvis Address -> Customer forsøges laves om til en one-one relation som det er garanteret i databasen vha unique index på Customer.AddressId, gives flg. design time fejl: Error 113: Multiplicity is not valid in Role 'Customer' in relationship 'FK_Customer_Address'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be *. Det er ikke direkt muligt at ændre access modifier på associationer i designeren, men det kan gøres manuelt i EDMX filen ved at tilføje GetterAccess og SetterAccess, eg.: <NavigationProperty Name="Lines" Relationship="MISModel.FK_OrderLine_Product" FromRole="Product" ToRole="OrderLine" cg:getteraccess="private" cg:setteraccess="private" /> EF modellerer one-one relationer via delte primary keys, ie. Customer og Address skal have samme primary key. Tilpasningen af denne model til den ønskede domæne model er derfor meget triviel, se. Figur 17, men i scenarier hvor man har meget store databaser kan dette godt blive uoverskueligt. Side 34 af 67

Figur 17 Entity Model efter tilpasning 8.3.1.3 Model First Ved denne metode oprettes en tom Entity Model, dette betyder at man skal oprette både den konceptuelle model og mapningen imod storage modellen. Hvis der ikke er en eksisterende database kan EF benyttes til at genrere denne ud fra mapningen. Side 35 af 67

Hvis man således ikke har en database og/eller har nogle specielle krav til denne, kan man benytte default mapningerne (convetion based) for nye entiteter og dermed få håndteret persistens med minimal indsats, ie. ved at designe sin konceptuelle model (dog vil der formodentlig skulle foretages mindre ændringer, eg. specificere længde på tekstfelter, etc.). 8.3.2 Refactoring Refactoring i EF foregår ved at det er muligt at ændre i den konceptuelle model (CM) som det ønskes (C# koden genereres på baggrund af denne), dvs. ændringer af property navne, kardinaliteter, klasse normaliseringer/denormaliseringer etc. Hvis der foretages ændringer af storage modellen (SM) kan dette kun pushes tilbage til databasen via en generering af et DDL (Data Definition Language) SQL script med udgangspunkt i en tom database dvs. det er ikke muligt at opdatere en eksisterende database med ændringer automatisk fra EF. 8.3.3 Learning Curve, Dokumentation og Community Som nævnt under 8.3.1.2 ovenfor er designeren rimelig intuitiv og hvis man har en generel forståelse af ORM er det meget simpelt at modellere en Entity Model. Der er dog visse elementer af modelleringen der (som nævnt) ikke er supporteret direkte i designeren, eg. specifikation af access modifier på associationer og modellering af table-per-concrete-class nedarvningshierarkier. Dokumentationen (tilgængelig online) er meget omfattende, og indeholder mange How-to s, Walkthroughs og Quickstarts til at komme godt igang. Edge cases som eg. modelleringen af table-per-concrete-class er ikke dokumenteret (28), (30). Generelt vurderes Entity Framework at være simpelt at komme igang med. Der er et rimelig levende online community omkring blogging etc. der omhandler EF, samt MS har på Data Developer Center et Community site til EF (34). Andre steder hvor man kan søge hjælp og support fra community et er eg. på StackOverflow (35). Side 36 af 67

9 NHibernate 9.1 Feature Evaluering Features evalueres ved hjælp af dokumentation og literatur (36) (37) og implementationen: Feature Supporteret? Kommentar Model first Ja En del af det grundlæggende koncept, Schema first Ja ie. at NHibernate at det blot er limen Code only Ja der faciliterer en et givet OOP system at persisteres i en givet relationel database One-one assoc. One-many assoc. Ja Ja Many-many assoc. Ja Supporterer også situationen med en explicit primary key, hvis denne blot autogenereres af databasen (eg. en identity kolonne) Table-per-hierarchy Ja (38) Table-per-concrete-class Ja (38) Table-per-class Ja (38) Mix nedarvings mapning Ja (38) Persistence Ignorance/Supporterede RDBMS Ja Mange supporterede, se (39) Lazy-loading Ja Via Ghost Objects, kræver at alle properties og metoder er deklareret som virtual LINQ Support Ja Ikke native (del af NHContrib (40)) For NHibernate foregår al mapningen i hånden, enten hvis man gør det via XML (HBM) filer, Fluent NHibernate eller den 3. mulighed ved at dekorere sin model med mapnings attributter. Side 37 af 67

9.2 Performance 9.2.1 SessionFactory NHibernate benytter sig af Unit-of-Work (8) design pattern til at holde (styr på) de objekter der loades fra databasen, ændringer, transaktioner, etc 7. Dette gøres via en session (et objekt der implementerer ISession fra NHibernate). En session initialiseres fra en klasse SessionFactory, som holder alt omkring mapninger, configuration, men genererer også de dynamisk Ghost Objects der benyttes til lazy-loading (5.6 ovenfor). Initialiseringen af SessionFactory er en tids-tung process. For vores simple model med 8 klasser, kan dette ses ved den første afviklede test i output er angivet: NHibernateTest - Setup: 00:00:03.4408842 I de efterfølgende tests tager dette (ca).: NHibernateTest - Setup: 00:00:00.0309500 Dvs. første initialisering af SessionFactory tager ca. 3,4 sekunder med 8 forholdvis simple klasser. Det betyder at for større modeller er opstarten (dvs. når AppDomain startes op, eg. ved opstart af en klient applikation, efter process recycling eller deployment af web applikation, etc.) forlænget med 3,4 sekunder pga. initialiseringen af NHibernate. Denne opstartstid er bla. afhænging af antal mappede klasser. 9.2.2 NHibernate og LINQ Hvis vi ser på flg. query til Customer_GetCategoriesForAllOrderedProducts(), som er besværliggjort af at Product.Lines ikke er med i modellen. var products = from o in uow.orderlines select o.product; var categories = products.selectmany(p => p.categories).distinct(); Assert.IsTrue(categories.Any()); Dette resulterer i flg. SQL statement: 7 Det gør sig også gældende for både LightSpeed og Entity Framework Side 38 af 67

SELECT count(* ) as y0_ FROM OrderLine this_ Hvilket tydeligvis ikke er korrekt. Problemet med dette er at C# koden kan compilere og rent C# kode mæssigt bør den give det korrekte resultat (ie. hvis vi udførte dette LINQ statement direkte på en in-memory collection af orderlines og dertilhørende objekt graf, ville vi gå hvad vi forventede). NHibernate s LINQ provider understøtter kun forholdsvis simple queries, dvs. hvis der skal eksekveres noget der er en lidt ud over SELECT * FROM Product WHERE Id =??, kan vi risikere at NHibernate ikke kan generere en korrekt query. Eller hvad der er endnu værre (som jo faktisk var tilfældet her), den genererer en forkert query og unit testen er successfuld på et forkert grundlag. Der er bevidst en lille fejl i koden, navnligt at der assertes på categories.any(). Dette er forkert da vi hermed laver.any() operationen en del af vores query (IQueryable), hvor testens faktiske formål er at vise at query resultatet giver Category objekter tilbage. Dette kan løses ved, som der også er i de andre tests, at udøre en.tolist() på IQueryable når den ønskes eksekveret, dvs. inden.any(). Assert.IsTrue(categories.ToList().Any()); Dette genererer nu en exception runtime. Test method MIS.Tests.NHibernateTest.Customer_GetCategoriesForAllOrd eredproducts threw exception: System.InvalidCastException: Unable to cast object of type 'MIS.NHibernate.POCO.OrderLine' to type 'MIS.NHibernate.POCO.Category'. Og flg. SQL statement bliver eksekveret: SELECT this_.id as Id1_0_, this_.quantity as Quantity1_0_, this_.orderid as OrderId1_0_, this_.productid as ProductId1_0_ FROM OrderLine this_ Dvs. projektionen select o.product ikke bliver fortolket korrekt. Side 39 af 67

Vi er i dette tilfælde nødt til at bruge HQL eller Criteria API for at generere en korrekt query. NB! Denne evaluering af NHibernate.Linq er baseret på den i skrivende stund nyeste version (frigivet i november 2009 kun 2. release), dette kan (og vil formodentlig) ændre sig over tid. 9.2.3 Ghost Objects Problem stillingen mht. Ghost Objects, nedarvning og LSP (se 5.6 ovenfor) eksisteter for NHibernate. Dette kan testes ved modellen, eg. følgende kode: Fejler med: var order = session.get<mis.nhibernate.poco.order>(1); Assert.IsInstanceOfType( order.customer, typeof(vipcustomer)); Assert.IsInstanceOfType failed. Expected type:<mis.nhibernate.poco.vipcustomer>. Actual type:<customerproxyb316635f117e466fabc43c186cfac9cf>. Customer med Id 1 er vel at mærke VipCustomer hvis vi vel at mærke tager udgangspunkt i en nyinitialiseret test database. Dette kan løses ved at eager loade Order.Customer, eller: In practice, this is something that you would generally run into when you are violating the Liskov Substitution Principle, so my general recommendation is to just fix your design. (41) 9.3 Implementation 9.3.1 Mapning Mapningen i NHibernate kan (som nævnt) foregå på 3 forskellige måder: 1) Via HBM i XML 2) Via FluentNHibernate (FH) Fluent Interface (42) hvor mapningen skrives vha. kode 3) Via Attributes (ikke testet) ved at dekorere sine klasser med attributter, eg. Side 40 af 67

[Class(Lazy=true)] public class Customer { [Id(Name = "Id")] [Generator(Class = "native")] public virtual int Id { get; set;} } [Property] public virtual string Name { get; set;} Alle 3 metoder skal gøres manuelt, i.e. HBM filerne skal skrives i hånden, FH mapningerne skal kodes eller attributterne skal tilføjes manuelt. Der findes dog værktøjer der kan hjælpe med at genrerere HBM filer (e.g Db2Hbm (43)) og fra HBM filer til klasser (Hbm2Net (44)) hvilket giver en Active Record (8) model. Dette giver i princippet samme udgangspunkt som en reverse engineered model i en designer, men for store/større domæne modeller kan det være meget svært at danne sig et overblik over klasser, associationer og nedarvningner vis HBM modellen. Til at redigere i HBM XML filerne er der XML Schema Definitions (XSD) tilgengængelig i NHibernate distributionen, som kan indlæses i eg. Visual Studio og opnå IntelliSense 8 i oprettelse/redigeringen af HBM filerne. FluentNHibernate er baseret på.net kode og mapningen er.net kode, så ifht. disse er der IntelliSense der kan hælpe ifht. mapningen af disse (det kræver dog at man er bekendt med udgangspunktet for mapningen, ie. klassen ClassMap<TEntity>). Der er naturligvis IntelliSense med Attribute tilgangen, her er hjælpen dog en smule mindre da man skal kende navnene (eller ihvertfald have en idé om hvad det kunne være) på de attributter man skal dekorere med. Mapningen i NHibernate er rimelig krævende både tidsmæssigt, forståelses og overbliks mæssigt. Det er ikke intuitivt og (som minimum) de første gange man skal mappe en database mod en model er det næsten givet at man skal have hjælp fra dokumentationen (som dog er meget god). 9.3.2 Querying I NHibernate er der 3 forskellige måder at skrive queries på: 8 IntelliSense er Microsoft s autocompletion i Visual Studio Side 41 af 67

1) LINQ som er beskrevet i 9.2.2 ovenfor 2) Hibernate Query Language HQL 3) Criteria API LINQ implementationen i NHibernate har som nævnt (i skrivende stund) sine problemer, det er eg. ikke muligt at lave dynamiske eager load (eg. for at undgå SELECT N+1) via en LINQ query. HQL er en SQL lignende syntax der bruges til at query mod NHibernate modellen. HQL er meget ekspressivt (45) og er den mest komplette query metode til NHibernate: HQL is how NHibernate exposes most of its power ( ) (46). Problematikken med HQL er dog at det er string baseret (stringly-typed, et pun på strongly-type (47)), ie. det parses runtime af NHibernate (vha. ANTLR (48)). Det betyder at der ikke er nogen compile time checking imod objekt-modellen om query er valid, hvilket betyder at det besværliggør refactorings ihvertfald ifht. at producere fejlfri refactorings. Lidt af samme problem er der med Criteria API, som er en hierarkisk opbygning af query i kode vha. et Fluent Interface (42). e.g. this.session.createcriteria<product>( product ).CreateAlias( product.categories, category ).Add(Expression.Eq( category.id, 2)).List<Product>(); Dette giver alle Product er i Category med Id = 2. Her er der igen benyttet magic strings der kan ændre sig med refactorings. Samlet set er quering via NHibernate meget expressivt, man kan stort set skrive alle former for queries. Det største problem ifht. at der er 3 metoder er at de har hver deres styrker, eg. HQL er det mest ekspressive, LINQ det mindst 9, hvorimod LINQ er det mest udvikler venlige (det er en velkendt query model) og der er compile time check af LINQ (dog er LINQ provideren som nævnt p.t. mangelfuld) 9 NHibernate.Linq oversætter LINQ queries til Criteria API som genererer SQL, ie. hvorfor opfinde den dybe tallerken?, men gør samtidig også at LINQ ikke kan blive mere expressiv end de begrænsninger der er i Criteria API. Side 42 af 67

queryen, så det er den option der er lettest at vedligeholde, hvorimod HQL er er den sværeste at vedligeholde, ie. udviklere skal lære HQL, og refactoring er besværlig gjort at magic strings og skal ske manuelt. Expressiv HQL Criteria API NHibernate.Linq Udvikling/vedligehold Figur 18 NHibernate query language optioner Dvs. man kan komme i en situation hvor man er skal blande query sprog (som det eg. er tilfældet i vores simple test, omend alt godt kunne være skrevet via HQL). Dette betyder mere overhead ifht. udvikling, og mindre vedligeholdbar kode. 9.3.3 One-Many inserts I one-many relationer er det nødvendig explicit at specificere Parent objekt på Child objektet selvom denne tilføjes explicit til Parent.Child collection. Eg.: var order = new Order(); order.lines.add(new OrderLine { Order = order }); 9.3.4 Learning Curve, Dokumentation og Community Som tidligere antydet er NHibernate forbundet med et stort overhead ifht. kodning og mapning. Både modellen og mapningen skal skrives i hånden, og specielt ifht. mapningen er det ikke intuitivt at komme i gang med. Der er som nævnt også nogle udfordringer med hensyn til at komme i gang med at skrive de første queries og det er under alle omstændigheder forbundet med lidt ekstra arbejde da man enten up-front skal beslutte hvilket query metode man benytter generelt, eller også skal der case-by-case vurderes hvilken query teknik er mest passende til det pågældende behov. Til NHibernates fordel på dette punkt taler dog for at det har det mest ekspressive querying sprog. NHibernates store fordel er dog at det har et meget, meget stort community, det har historikken med sig (ie. der er med stor sandsynlighed andre der har oplevet Side 43 af 67

de samme fejl/udfordringer som man selv kunne støde på) og det lukrerer på synergien med det mindst ligeså store Java Hibernate community. Selvom NHibernate er en portering af Hibernate er features, etc. holdt i sync for at kunne opnå denne synergi effekt. Synergi effekten er også ifht. dokumentation. En stor del af dokumentationen e.g. HBM og HQL er ens for både Hibernate og NHibernate og der behøves derfor kun at vedligeholdes ét sæt kvalitets dokumentation for disse. Tidligere har NHibernate være anklaget for manglende dokumentation, på trods af at der er glimrende dokumentation tilgængelig (49). Support scenarier kan oftest være en show-stopper for Open Source adoption i store eller større virksomheder, til dette tilbyder NHibernate (via Hibernating Rhinos) (50) en kommerciel support option. 9.3.4.1 Addon libraries NHibernate community omfatter ikke blot support, blogs og hjælp. Der er også flere 3rd party add-on libraries til NHiberate. Der kan eg. nævnes: NHibernate.Validator data validerings framework, findes både som attribute baseres og som et fluent interface NHibernate.Search full text search engine baseret på Lucene.NET indexes NHibernate.Burrow transaction management, etc. bla. i ASP.NET (stateless) baserede miljøer FluentNHibernate fluent interface til mapning 10 LightSpeed 10.1 Feature Evaluering Features evalueres ved hjælp af dokumentation (51) for LightSpeed og implementationen: Feature Supporteret? Kommentar Model first Schema first Ja Ja Side 44 af 67

Code only Nej Alle entiteter nedarves fra Entity<TId>, hvor TId er typen af den primary key/id. One-one assoc. Ja One-many assoc. Ja Many-many assoc. Ja Supporteres via såkaldte Through Entities, dvs. principelt skal link tabellen mappes til en entity (dette kan dog håndteres automatisk af frameworken), men der kræves en explicit id på link tabellen. Table-per-hierarchy Ja Single Table Inheritance Table-per-concrete-class Ja Concrete Table Inheritance, dette er ikke nævnt i dokumentationen, men det er muligt at vælge via designeren. Table-per-class Ja Class Table Inheritance, kræver en discriminator column på superklasse tabellen. Der er dog (formodentlig) en fejl i frameworket der gør at dette ikke virker hvis subklasse tabellerne ikke ligger i default skema. Mix nedarvings mapning Ja Persistence Ignorance/Supporterede RDBMS Ja Amazon SimpleDB, DB2, FireBird (deprecated), MySQL, Oracle, PostgreSQL, SQL Server, SQL Server CE, VistaDB enkelte med begrænset designer funktionalitet Lazy-loading Ja Via en inherited baseclass (alle entiteter nedarver fra Entity<Tid>) LINQ Support Ja 10.2 Performance 10.2.1 Eager Loading Hvor NHibernate (pr. default) bruger JOIN til Eager Loading, Entity Framework bruger SUBSELECT, så tager LightSpeed en 3. approach: multi queries. Dette vil betyde for Eager Loading på fx. Order -> OrderLine -> Product vil blive eksekveret flg. 3 (forkortede) SQL statements (i én batch!): Side 45 af 67

SELECT [Order]... FROM [Order] WHERE [Order].[Id] = 1; SELECT [OrderLine]... FROM [OrderLine] WHERE [OrderLine].[OrderId] = 1; SELECT [Product]... FROM [Product] WHERE EXISTS ( SELECT [OrderLine].* FROM [OrderLine] WHERE [OrderLine].[ProductId] = [Product].[Id] AND [OrderLine].[OrderId] = 1 ) En simpel test af 1.000 iterationer på denne viser at LightSpeed bruger ca. 4,3s, EF ca. 6,1s og NH ca. 8,3s. (dvs. 1 eksekvering tager ca. det samme i ms). 10.2.2 LINQ I forbindelse med querying kom LightSpeed s LINQ implementation til kort overfor Customer_GetCategoriesForAllOrderedProducts(). Iflg. det direkte LINQ query: var products = from o in uow.orderlines select o.product; var categories = products.selectmany(p => p.categories).distinct(); Som gav fejlen: Mindscape.LightSpeed.LightSpeedException: Could not locate reverse association model Side 46 af 67

Men ifht. mapningen er begge retninger af associationen tilgængelig (det er de altid i LightSpeed), og faktisk er Product.Lines public i denne model. Dette kan umiddelbart dog løses, omend det ikke er en god løsning, ved at forcere eksekvering af Product query en og udføre SelectMany(p => p.categories) på denne. Dette resulterer dog i en SELECT N+1, og det er ikke muligt at lave Named Aggregates (som bliver uddybet i 10.3.2 nedenfor) på en many-many relation, så denne løsning er ikke holdbar, specielt hvis der er tale om ret mange Product s. 10.3 Implementation 10.3.1 Mapning Mapningen foregår (som for Entity Framework, 8.3.1) via en designer integreret i Visual Studion. En LightSpeed model er som udgangspunkt tom, men der kan på tilsvarende måde som ved Entity Framework laves en reverse engineering af databasen, ved blot at drag-n-droppede ønskede tabeller ind fra en database via Server Explorer i Visual Studio. I Figur 19 er et eksempel på en reverse engineered database model fra eksemplet i 7.2 ovenfor. Side 47 af 67

Figur 19 Auto genereret LightSpeed Model Mapningen er rimelig intuitiv og kræver (igen tilsvarende Entity Framework) kun minimal kendskab til koncepterne for ORM, for at kunne modellere en rimelig simpel model. I modsætning til Entity Framework designeren er det muligt at foretage al mapningen via designeren, omend table-per-class (3.3.3) og table-per-concreteclass (3.3.2) mapningerne ikke har kunne bringes til at fungere (dette er dog absolut ikke nødvendigvis en fejl ved LightSpeed). Det er muligt at designe sin objekt-model udenfor designeren, men LightSpeed har som krav at entiteter skal baseres på Entity<TId> baseclass en, hvilket udelukker en POCO tilgang (5.3) til ORM via LightSpeed. Model first (5.1) og Schema first (5.2) er begge mulige via designeren (ie. reverse engineering af tabellerne er ikke nødvendigt for at lave mapningen). LightSpeed har som det eneste framework indbygget data validering, dette kan selvfølgelig ses som både en styrke og en svaghed, eg. ifht. begrænsninger i validation (LightSpeed er ikke et validering framework men en ORM). Dog kan Side 48 af 67

man benytte et andet validerings framework ovenpå, hvis LightSpeed s ikke er tilstrækkelig. 10.3.2 Eager loading LightSpeed tilgang til eager loading er meget intuitiv. Der kan enten (som ved alle 3 ORM) specificeres på relationer at disse loades Eager, dvs. sammen med parent objektet. Alternativt kan man i LightSpeed designeren angive Named Aggregates, for associationer. På selve query kan man angive at benytte en Named Aggregate, hvilket betyder at associationer med dette navn bliver Eager loaded, eg.: var order = uow.orders.withaggregate("alllines").single(o => o.id == 1); Idet AllLines er Named Aggregate på Order -> OrderLine associationen, vil ordre linier blive eager loaded sammen med ordren. Det er ikke muligt at bruge Named Aggregates sammen med FindById<TEntity>(id)og heller ikke for many-many relationer, hvorfor det er nødvendigt at bruge ovenstående LINQ syntax, dette kan være lidt uhensigtsmæssig da man skal bruge to forskellige metoder til at opnå det samme (ie. load et objekt ind via ID). 10.3.3 Learning Curve, Dokumentation og Community LightSpeed er rimelig let at komme igang med, reverse engineering af databasen og refactoring af modellen via designeren er meget intuitiv. LightSpeed har ikke det samme community som hverken Entity Framework og slet ikke som NHibernate. Dette gør at hjælp stort set er begrænset til MindScape s website og de officielle support kanaler (den kommercielle licens til LightSpeed tilbyder priority support). Dokumentationen på websitet er meget mangel fuld, eg. der er kun how-to dokumentation for mapningen og de simpleste querying scenarier. Side 49 af 67

Der forefindes dog nogle gode screencasts der hjælper på at komme igang, og en rigtig god feature er at der indbygget i designeren kan genreres configuration og kode til setup af context etc. Figur 20 Getting Started with LightSpeed integreret i designeren 11 Sammenfatning LINQ til NHibernate er mangelfuld i sin nuværende inkarnation, dvs. man kan ikke lave en fuld applikation med selektive Eager Loading via LINQ interfacet eller hvis man benytter en smule komplicerede LINQ queries kan man ikke være sikker på at det virker efter hensigten (før det eksekveres runtime). Nedarvning er lettest i NHibernate, eg. i EF4 skal man redigere i EDMX filen manuelt for at supportere table-per-concrete class. LightSpeed har ikke kunne bringes til at fungere med de to mest komplicerede nedarvningsskemaer (og dermed heller ikke i det mixede scenarie). NHibernate er den bedste ORM til Schema First, eg. både LS og EF4 stiller krav omkring many-many link tabellen LS skal have en explicit primary key, EF4 kan ikke have en explicit primary key. Side 50 af 67