Και σήμερα με ρώταγε κι άλλος για το ίδιο πράγμα! Μιλημένοι είσαστε? (Τί κρατάει ο Ναπολέων?). Αν ψάξεις για ORM στο DNZ θα δεις κάποιες συζητήσεις, ενώ υπάρχει και το How to Select an Object Relational Mapping το οποίο είναι λίγο παλιό. Από τότε όλα σχεδόν τα εμπορικά ORM έχουν φτάσει στο ίδιο περίπου σημείο.
Γιατί δυναμικά queries? Ως τώρα έχω δεί τρεις λόγους για τη χρήση δυναμικών queries. Ad-hoc search, προσπάθεια δημιουργίας Data Layer με χαρακτηριστικά ORM, ή δημιουργία business entity framework. Το ad-hoc search δεν το γλυτώνεις. Αν όμως χρησιμοποιήσεις κάποιο ORM, τα δυναμικά queries και τα joins θα τα κάνει το ίδιο το ORM. Η δημιουργία business framework είναι μία άλλη μεγάλη συζήτηση, την οποία δεν θέλω να ξεκινήσω αν δεν σε ενδιαφέρε. (Όπως θα καταλάβεις σε λίγο, όταν αρχίσω δύσκολα σταματάω).
Ένα αντικείμενο μπορεί άνετα να γίνει mapped σε πολλούς πίνακες. Σε περίπτωση μάλιστα που θέλεις να αποθηκεύσεις κλάσεις οι οποίες έχουν σχέσης inheritance ένα αντικείμενο μπορεί να καταλήξει να αποθηκεύεται σε 1, 2 ή περισσότερους πίνακες ανάλογα με το μοντέλο inheritance mapping που επιλέγεις. Το mapping αυτό συνήθως το ορίζεις σε ένα mapping αρχείο αν και υπάρχουν μεγάλες διαφορές από εργαλείο σε εργαλείο. Το LINQ to SQL για παράδειγμα έχει γραφικό περιβάλλον, το NHibernate έχει xml mapping file, αν και υπάρχουν μερικοί designers, άλλα εργαλεία έχουν τα δικά τους.
Το τί ORM θα επιλέξεις εξαρτάται από το τί θέλεις να το κάνεις. Για παράδειγμα, το Subsonic κάνει πολύ εύκολα mapping και generation των data objects, δεν τα πάει όμως καθόλου καλά με το concurrency. Είναι καλό για internet/intranet web sites, κακό για web applications και transactional συστήματα. Το NHibernate θέλει χρόνο να το μάθεις αλλά έχει υποστήριξη για inheritance mapping, concurrency της επιλογής σου, lifecycle management (πότε και για πόση ώρα θα είναι ανοικτά τα connections?), lazy ή eager loading (φορτώνω όλα τα αντικείμενα ενός collection με τη μία ή όταν τα ζητήσω?), long transactions (transactions τα οποία έχουν ισχύ ακόμα και όταν κλείσει το connection από το οποίο τραβήχτηκαν τα δεδομένα). Είναι πολύ καλό για transactional συστήματα και web applications. Έχει πολύ μεγάλη αποδοχή από τους C# developers οπότε μπορείς να βρεις σχεδόν πάντα κάποιον που θα έχει δουλέψει στα σενάρια που σε ενδιαφέρουν.
O άλλος σημαντικός παράγοντας είναι ποιοί θα το χρησιμοποιήσουν? Όποιος δεν έχει δουλέψει με transactional συστήματα ή δεν καταλαβαίνει από patterns θα δυσκολευτεί να καταλάβει το πως δουλεύουν τα πιο προχωρημένα ORMs και το γιατί. Άς πάρουμε για παράδειγμα το eager/lazy loading. Αν έχεις μία κλάση με 50 πεδία τα οποία είναι επίσης κλάσεις, θέλεις να φορτωθούν όλα όταν φορτώσεις την parent κλάση, ή μόνο όταν το ζητήσεις? Αν φορτωθούν όλα, θα δημιουργηθεί ένα SQL statement σεντόνι, θα κτυπήσεις όμως τη βάση μόνο μία φορά. Αυτό είναι το eager loading. Αν τα φορτώσεις μόνο όταν τα θέλεις, θα εκτελούνται συχνά πολλά μικρά statements. Αυτό είναι το lazy loading. Αν δουλεύεις σε ένα collection από αντικείμενα, το lazy loading μπορεί να σου κοστίσει πολύ ακριβά σε round trips. Το eager loading μπορεί να φορτώνει πολλά πράγματα με τη μία αλλά να έχει καλύτερο scalability από το lazy loading - ή όχι.
Για transactional και scalable συστήματα θα πρέπει να χρησιμοποιήσεις κάποιο προχωρημένο ORM όπως το NHibernate ή το ADO.NET Entity Framework και να το δώσεις σε senior προγραμματιστές. Για web sites και RAD development μπορείς να δώσεις ένα απλούστερο όπως το Subsonic ακόμα και σε junior προγραμματιστές.
Το LINQ to SQL μπορεί να παίξει και στις δύο κατηγορίες, αν και για τα transactional συστήματα θα πρέπει να γράψεις επιπλέον κώδικα για το concurrency, lifecycle κλπ που θέλεις. Το καλό με το LINQ είναι ότι μπορείς να το χρησιμοποιήσεις παράλληλα με όποια άλλη λύση ORM επιλέξεις, π.χ. για να φορτώνεις lookup δεδομένα ή να φορτώσεις αντικείμενα τα οποία δεν χρειάζονται τις επιπλέον υπηρεσίες που δίνει ένα ORM.
Παναγιώτης Καναβός, Freelancer
Twitter: http://www.twitter.com/pkanavos