Καταρχήν, να παρακαλέσω τον kos6101991
serakar να χρησιμοποιεί code blocks (είναι το τρίτο εικονίδιο από το τέλος του δεύτερου toolbar, αυτό με τα {} ) για να μπορεί να διαβαστεί ο κώδικας.
Μετά, να παρατηρήσω ότι οι λύσεις που δόθηκαν ως τώρα είναι επικίνδυνες για τον γνωστό λόγο του SQL injection και θα αποτύχουν σίγουρα σε περιβάλλον με ελληνικά local settings. Είτε κάνει κάποιος string concatenation, είτε κάνει String.Format, η τιμή 0.6 στα ελληνικά θα μετατραπεί σε 0,6 και το SQL θα αποτύχει.
Όσο για το SQL Injection, αν η τιμή z προέρχεται από user input, μπορεί άνετα ο χρήστης να βάλει κάτι "έξυπνο" όπως "0;drop table XXX; --" και να κάνει ζημιές.
Για το λόγο αυτό ΔΕΝ ΠΡΕΠΕΙ ΠΟΤΕ να δημιουργούμε sql strings με concatenation ή String.Format (το ίδιο είναι εξάλλου).
Ο σωστός (και ευκολότερος και ταχύτερος) τρόπος να περάσει κανείς παραμέτρους σε SQL είναι με parameterized queries:
using(var conn = new SqlConnection(@"Data Source=KOSTAS-PC;Initial Catalog=form;Integrated Security=True"))
{
var cmd = new SqlCommand("update krithrio1 set y=@y where x=@x", conn);
cmd.Parameters.AddWithValue("@y", 0.6);
cmd.Parameters.AddWithValue("@x", 25);
conn.Open();
cmd.ExecuteNonQuery();
}
Ο παραπάνω κώδικας στέλνει τις παραμέτρους στο server με τον αρχικό τους τύπο, χωρίς μετατροπές σε string, με αποτέλεσμα να είναι αδύνατο το SQL Injection. Επίσης αποφεύγονται οι μετατροπές οπότε δεν έχουμε προβλήματα με υποδιαστολές. Τέλος, είναι πολύ ταχύτερος γιατί αφενός αποφεύγονται οι μετατροπές, αφετέρου ο server μπορεί να κρατήσει το ίδιο compiled query για αναφορά στο μέλλον, χωρίς να ξανακάνει compile. Επιπλέον, μεταφέρει λιγότερα bytes απ' ότι αν μετατρέπαμε την αντίστοιχη τιμή σε string.
Όλα αυτά τα οφέλη αθροίζονται όσο τρέχει μία εφαρμογή και μπορεί να γλυτώσουν χρόνο που ξεπερνάει ακόμα και το 50% αν γίνονται συχνές όμοιες κλήσεις στη βάση.
Προβλήματα μετατροπής εμφανίζονται και όταν κανείς χρησιμοποιεί ημερομηνίες ή unicode strings με ελληνικό κείμενο. Χρησιμοποιώντας parameterized queries το πρόβλημα λύνεται άμεσα και ο κώδικας είναι λιγότερος.
Προσοχή τέλος στο using. Οι ανοικτές συνδέσεις στις βάσεις κοστίζουν, γι αυτό και πρέπει να τις κλείνουμε πάντα. Το using φροντίζει να κλείσει η σύνδεση ακόμα και αν υπάρξει exception. Διαφορετικά θα πρέπει να περικλείσουμε το block σε ένα try/finally το οποίο θα ελέγχει αν άνοιξε η σύνδεση και θα την κλείνει στο finally.
Παναγιώτης Καναβός, Freelancer
Twitter: http://www.twitter.com/pkanavos