Update foreign keys μέσω linq.

 Καλησπέρα σε όλους. Είχα υποσχεθεί στον εαυτό μου και στο Forum να μοιραστώ μαζί σας την γνώση που βρήκα σχετίκα με την αλλαγή τιμών των ξένων κλειδιών με χρήση της linq και τώρα ήρθε η μεγάλη ώρα.

Ας ξεκινήσουμε κάνοντας μερικές παραδοχές:
α)Έχουμε τους πίνακες cars και orders.
β)Στον πίνακα orders εκτός όλων των άλλων έχουμε foreign key το id του αυτοκινήτου που θα παραγγείλουμε.
γ)Ενα καλό πρωί ο πελάτης αλλάζει άποψη και θέλει να παραγγείλει διαφορετικό αυτοκίνητο, οπότε πρέπει να αλλάξουμε την τιμη του foreign key στον πίνακα order.'
δ)Ολόκληρη η εφαρμογή μας δουλεύει με LINQ.

Αν νομίζετε οτι είναι απλά τα πράγματα ειστε απλά ΓΕΛΑΣΜΕΝΟΙ....

Για να πετύχουμε κάτι τέτοιο η Linq είναι εξαιρετικά ιδιότροπη και μας αναγκάζει να αλλάξουμε την τιμή μέσω του αντικειμένου της κλάσης πατέρας που στην περίπτωση μας είναι η κλάση cars και αλλάζοντας την σύνδεση των εγγραφών και όχι απευθείας την τιμή. Οπότε ενδεικτικά θα είχαμε:

 

 VOILA!!!!!! Μόλις άλλαξα την παραγγελεία απο focus σε mondeo για τον κύριο bilia.
Αυτός λοιπόν είναι ο μόνος τρόπος που δούλεψε για μένα και σας προκαλώ να βρείτε κάτι πραγματικά πιο εύκολο για να πειστώ οτι αυτοί που έστησαν την τέλεια κατα τα λοιπά linq δεν το είχαν στόχο να μας βασανίζουν με τα foreign keys....!
Ελπίζω να βοηθήσω όσους θα ασχοληθούν, γιατί δεν υπάρχει καθαρή λύση πουθενά στο internet και πραγματικά μου άλλαξε τα φώτα αυτο το update.....!

Bilias7 member of eRecycle team. Let's develop the meaning of freedom...! Όποιος ελέυθερα συλλογάτε, συλλογάτε καλά. Ρ.ΦΕΡΑΙΟΣ

4 Replies

  • Αντιμετωπίζεις δυσκολίες γιατί χρησιμοποιείς ένα ORM όπως είναι το LINQ to SQL με εντελώς λάθος τρόπο. Η βασική έννοια σε ένα ORM είναι οι κλάσεις και όχι οι πίνακες. Δεν υπάρχουν foreign keys, υπάρχουν properties και collections. Μπορεί το LINQ to SQL κακώς να εμφανίζει τα foreign keys ως properties επάνω στο αντικείμενο, άλλα ORM όπως το Entity Framework και το NHibernate δεν το κάνουν.

    Το μόνο που χρειάζεται για να αλλάξεις το αυτοκίνητο μίας παραγγελίας, έστω της myOrder, είναι να γράψεις myOrder.Car=newCar. Θεωρώ ότι υπάρχει το property Car στην κλάση order και ότι το newCar είναι το νέο αυτοκίνητο που θέλες να χρησιμοποιήσεις. Το μόνο που μένει είναι να φορτώσεις πρώτα την παραγγελία για το συγκεκριμένο πελάτηκαι μετά το νέο αυτοκίνητο από τη βάση. Αν όμως έχεις ήδη φορτώσει τον πελάτη, και ο πελάτης έχει ένα property Orders, το μόνο που χρειάζεται να κάνεις είναι να ψάξεις στην Customer.Orders για την παραγγελία που σε ενδιαφέρει.

    Σε κάθε περίπτωση, ο κώδικας είναι πολύ απλούστερος από αυτό που έγραψες, απλά γιατί προσπάθησες αντί για αντικείμενα να χρησιμοποιήσεις πίνακες - και πίνακες σε ένα ORM δεν υπάρχουν.΄

    Ο κώδικας θα μπορούσε να γραφτεί πολύ απλά:

    Επίτηδες δεν ονόμασα το context db όπως έκανες εσύ γιατί δεν αντιπροσωπεύει ούτε τη βάση ούτε το connection προς τη βάση. Αντιπροσωπεύει ένα object model.

    Παρεμπιπτόντως, αν ερχόσουν στα event του DotNetZone για τα ORM όπως αυτό που θα γίνει την Τετάρτη, δεν θα είχες την απορία.

  • In reply to Παναγιώτης Καναβός:

     Παραδέχομαι ήττα αλλά και αυτό μου φαίνετε υπερβολικά πολύπλοκο!!! Γενικά δεν καταλαβαίνω γιατί έβαλαν αυτον τον περιορισμό και δεν μπορώ να αλλάξω απευθείας το foreign key.
    Εν τέλει πάντως κάνεις περίπου αυτό που έκανα και εγώ αποσύνδεση και σύνδεση 2 αντικειμένων απλά πολύ πιο έξυπνα εντοπίζεις και χρησιμοποιείς τα αντικείμενα....!

    Οσο για τα event που μου προτείνεις τώρα άκουσα την ύπαρξη τους και θα σας τιμήσω απο το επόμενο γιατι την Δευτέρα έρχομαι Αθήνα...!

    Bilias7 member of eRecycle team. Let's develop the meaning of freedom...! Όποιος ελέυθερα συλλογάτε, συλλογάτε καλά. Ρ.ΦΕΡΑΙΟΣ
  • In reply to Bilias7:

    Foreign keys? Ποιά foreign keys? Τα αντικείμενα δεν έχουν foreign keys! Έχουν κλάσεις, properties, μεθόδους. Αν δεν δουλεύεις με αντικείμενα, είναι λογικό να σου φαίνεται πιο "πολύπλοκη" η  κατάσταση καθώς προσπαθείς να χρησιμοποιήσεις αντικείμενα ως πίνακες. Αν δουλεύεις όμως με αντικείμενα, όπως θα έπρεπε, είναι εξαιρετικά απλό να πείς myOrder.Car=newCar.

    Μπορεί το παράδειγμα σου να είναι τόσο τετριμμένα απλό ώστε να φαίνεται ότι θα μπορούσες απλά να αλλάξεις κάποιο foreign key. Τί γίνεται όμως αν κάποιος έχει παραγγείλει φορτηγό? TIR? Αυτό το φορτηγό ορυχείων από την Caterpillar? Είναι σχεδόν σίγουρο ότι αποκλείεται να χρησιμοποιήσεις την ίδια κλάση για όλες αυτές τις περιπτώσεις. Είναι πολύ πιθανό ότι θα χρειαστείς μία γενική κλάση Car και subclasses HighwayTruck, MiningTruck, PassengerCar κλπ. Για παράδειγμα, για ένα Smart κρατάς κυβικά, αλλά για ένα 797Β φορτηγό ορυχείων θα κρατάς ισχύ και ωφέλιμο φορτίο. Και πάλι όμως, θα γράψεις myOrder.Car=newCar.

    Η τεχνική που παρουσιάζεις είναι εντελώς περιττή καθώς ο σωστός και απλούστατος τρόπος είναι απλά να θέσεις την τιμή ενός property και να σώσεις. Θα συνιστούσα σε οποιονδήποτε προσπαθεί να δουλέψει με foreign keys σε ένα ORM να σταματήσει και να καταλάβει πρώτα την λογική του εργαλείου αλλά και του Object Oriented Design. Διαφορετικά θα αντιμετωπίζει πάντα προβλήματα.

    Σαν να προσπαθείς να καρφώσεις μία βίδα.

  • In reply to Παναγιώτης Καναβός:

    Μάλλον κάπου μπερδευτήκαμε λίγο... Καταρχήν Παναγίωτη δεν σε ξέρω, δεν αμφισβητώ τον όγκο των γνώσεων σου πάνω στο θέμα και καμία διάθεση να διαφωνώ μαζί σου έχω αλλά μου τα λές περίεργα τα πράγματα και πρέπει να απαντήσω για να καλύψω την θέση μου.... Έχω πολύ καλά στο μυαλό μου τι σημαίνει Object Oriented Design και ακόμα καλύτερα τι ακριβώς είναι κλάσεις - υποκλάσεις κληρονομικότητα και όλα αυτά τα πράγματα!!! Όμως δεν μίλησα γενικά για ένα αντικειμενοστραφές πρόγραμμα, μίλησα για την Linq που δημιουργήθηκε για να απλουστεύσει την χρήση μίας DATABASE... Απο την στιγμή λοιπόν που έχουμε database και με αυτήν ασχολούμαστε μέσω των κλάσεων που πανέξυπνα δημιουργεί η linq μην μου λέτε οτι δεν έχουμε foreign key και οτι καρφώνω βίδες....! Αν θέλω να ασχοληθώ με δικιά μου εφαρμογή και να φτιάξω δικές μου κλάσεις τότε ναι αλλά η Linq χτυπάει σε βάση άρα για να δουλέψει πρέπει να είναι σύμφωνη με τους κανόνες της βάσης.... Επίσης πρέπει να σου θυμίσω οτι το exception που πετάει το πρόγραμμα είναι "FOREIGNkEY rEFERENCE aLREADY hAS vALUE eXCEPTION" αρά αφού απο μόνη της η Linq ασχολείτε με ξένα κλειδιά οτι και να πούμε παραπέρα είναι περιττό....!
    Αλλά οκ να σού δώσω τον κώδικα όπως τον είχα στήσει και δεν δούλευε και να μου εξηγήσεις μόνο με αρχές Object Oriented Programming χωρίς να αναφέρεις database γιατί δεν έτρεχε....


    Αυτός ο κώδικας πέταγε το θρυλικό "FOREIGNkEY rEFERENCE aLREADY hAS vALUE eXCEPTION".....!

    Bilias7 member of eRecycle team. Let's develop the meaning of freedom...! Όποιος ελέυθερα συλλογάτε, συλλογάτε καλά. Ρ.ΦΕΡΑΙΟΣ