09. august 2004 - 16:46Der er
51 kommentarer og 2 løsninger
Overblik over ADO.net
Jeg er gået i gang med at lave en klasse der kan håndtere databaseforespørgsler. Det skal være en klasse der skal bruges i mange forskellige applikationer, dvs. et dll-lib jeg inkluderer, som så utrolig let og fleksibelt kan håndtere al DB-adgang. Jeg mangler dog at få et totalt overblik over de forskellige DB-muligheder og faciliteter der er i .net. Jeg er godt klar over at der er en MASSE faciliteter, så det ville jo være smart at ha en klasse der kunne tage sig af de mest gængse funktioner . Jeg kunne desuden godt tænke mig at klassen kunne tage sig af ting som SQL-injection og ConnectionPooling. Så selvfølgelig specialiserede forespørgsler hvor der kun kommer 1 record tilbage osv. Jeg kan jo nok ikke undgå at jeg er nødt til at retunere fx. en datareader fra en SQL-SELECT og sådan...som jeg så er nødt til at behndle udenfor objektets scope. Men sådan er det jo bare. Det jeg bare gerne vil stræbe efter er at al DB-behandling bliver håndteret inde i min DBHandler klasse. Noget andet den også skulle kunne var at gøre brugen af OLE-DB og MS SQL tilgang ret let, således at man kun behøver sende en parameter fx. der afgør om der skal bruges SqlClient el. OleDb. ALle disse ting kræver jo altså overblik, så mit spørgsmål er om nogle kender rigtig gode steder hvor jeg kan læse om alt det her. Evt. hvis der findes noget kode i forevejen der kan alt det her...Det e rvel et ret generelt problem og ellers bare gode fif, tricks og code snippets.... Håber jeg har udtrykt problemet klart nok. Mvh. bumle90
ahhh okay...det er sq da supersmart...Jeg går ud fra den laver en form for replace af plinger osv. Altså en art encoding. Hvad så når det skal ud af DB igen...skal det så decodes igen på en måde når der er brugt parameters?
Et andet spg. jeg håbede du ville svare på er om der er en smart måde at genbruge sin connection på i en webapp istedet for at oprette en ny hver gang? Altså fx. i din MultiDb-klasse ville det kræve at man hver gang en ny side var loadet skulle initialisere objektet igen...lave ny forbindelse osv. som man så kunne bruge. Er der ikke en smartere måde...således at jeg kan bruge mit connection objekt gennem et helt forløb? Skal jeg gemme det i en sessionsvariabel eller hvad er smart? Jeg tænker sådan rent performancemæssigt hvad der er smartest?
Okay, så dvs. det klogeste er at i page_load på alle mine sider(der bruger DB) at lave et nyt DB-objekt, og gemme det i en global public klassevariabel?
Grunden til jeg vil lave det public er fordi jeg instantierer andre klasser i min page-klasse som også skal bruge databasen....lidt dumt hvis jeg har connection objekter i alle de klasser jo
hmm johh problemet er at jeg har bygget mit design op med tanke på andre ansvarsområder. Fx. en række objekter der opbygger dynamisk pdf-filer. De skal bruge data fra databasen. Så dem er jeg næsten nødt til at ha for sig selv. Så er der nogle drop-downs der skal bruge databasen, og endelig skal jeg også lave et datagrid der gør brug af DB. egentlig får jeg kun 2 steder jeg skal bruge db så. Måske er det bedre at sende DB-objektet med til konstruktøren for pdf-objekterne. Og så ellers oprette objektet i de forskellige page_load. Så ellers bare gemme det i en privat instans variabel. Hvad siger du til det?
En anden (som nok primært er interessant ved lav volumen) er at lave en 1-2-3-4 singleton klasser med hver sin connection og metoder som bruger lock på den til at sikre at kun en enkelt operation foretages af gangen.
Min kode for min DBHandler er so far følgende: (Der skal bygges lidt videre på den efterhånden som der kommer flere behov, men hvad synes du om den som udgangspunkt?(Der er et problem med at lukker connection efter hver tilgang...)
using System; using System.Data; //using System.Data.Common; //using System.Data.Odbc; using System.Data.OleDb; using System.Data.SqlClient; //using System.Data.SqlTypes;
namespace certregister { /// <summary> /// Summary description for DBHandler. /// </summary> public class DBHandler { private string connectionstring; private OleDbConnection OleConn; public static int SQLSERVER=0; public static int OLEDBSERVER=1;
public static String SQLEncode(String val) { return(val.Replace("'","''")); }
public DBHandler(string dbpath,int DBtype) //kaster alle exceptions videre { //connectionstring = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source="+dbpath; if(DBtype==OLEDBSERVER) { connectionstring = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source="+dbpath; OleConn = new OleDbConnection(connectionstring);//(connectionstring); OleConn.Open(); } }
public OleDbDataReader fetch(string sql) { OleDbCommand comm = new OleDbCommand(sql, OleConn); OleDbDataReader r = comm.ExecuteReader(CommandBehavior.CloseConnection); return(r);
okay, men jeg kan ikke forstå hvorfor den kommer med fejl når jeg laver flere på hinanden følgende fetch. Så siger den connection obejctet er blevet lukket. Hvis jeg skifter følgende linie comm.ExecuteReader(CommandBehavior.CloseConnection); ud med fx. comm.ExecuteReader(CommandBehavior.SingleResult); Brokker den sig istedet over at der eksisterer datareader i forvejen. Hvad gør jeg forkert? "There is already an open DataReader associated with this Connection which must be closed first"
okay, er det smart at retunere en System.Data.IDataReader? Altså jeg mener bare hvis man ser sådan ideelt på det bør alt databasebehandling jo foregå inde i DB-handleren. Dvs. der bør ikke engang importes nogle DB-namespaces andre steder end i DB-handleren. For sådan som det er nu er jeg jo nødt til at bruge fx. System.Data.IDataReader uden for DBhandleren....inde i selve applikationen. Men jeg kan også godt se at det blir lidt noget rod hvis man skal til at kopiere hele settet over i en eller anden datastruktur først for at retunere den istedet. Det er faktisk lidt et problem jeg har tænkt over et par gange. Hvad er den "rigtige" så at sige, løsning på det problem?
Hmmm luk datareaderen inden næste kald....Der må da være en pænere måde at gøre det på. Ellers er jeg nødt til at gemme min datareader i en midlertidig variabel for kunne lukke den. Altså fx. her(Dette illustrerer også meget godt hvad jeg mener med det jeg skrev før)
selWelderMethod.DataSource=dbHandler.fetch("SELECT SVmetode FROM T_SvMetode"); selWelderMethod.DataTextField="SVmetode"; selWelderMethod.DataBind();
Her er det eneste DB-specifikke SQL-strengen der sendes med. Hvis jeg skal lukke readeren er jeg nødt til at lave en datareader-reference som jeg så kan bruge til at lukke den med. Det virker bare ret omsonst på enelleranden måde synes jeg....Er du med på hvad jeg mener?
Det er bedre at returnere en IDataReader end en connection specifik klasse.
Enten returnerer du en reader og processer data udenfor database klassen eller du returnerer en collection (ArrayList, Hashtable eller lignende) med data.
hmm ja oki...jeg kunne jo selvfølgelig bare lave 2 fetch. En der retunerer IDataReader og en der retunrer en Hashtable...Så kan man jo selv vælge hvilken man vil bruge...
Jeg tænker umiddelbart i retning af: - et antal commands instantieres i constructor - hver command har en metode som kaldes med det antal parametre der skal sættes
Hmmm hvad mener du med et antal commands? At man definerer alle sine sql i DB-handleren? Hvad så hvis den skal bruges i flere forskellige applikationer? Man har jo fx. en sql-streng "SELECT blabla WHERE bla='her er en fare' AND bla2 LIKE 'her er endnu en fare'" Man ved jo ikke på forhånd hvilke og hvor mange parametre i sql-strengen der skal encodes... Og der er heller ikke smart hvis man skal til at lave command-strengen udenfor db-objektet...Det er ret svært egentlig
Kunne man ikke lave et interface der specificerer en klasse man blir nødt til at implementere for den enkelte applikation...Denne klasse indeholder så samtlige sql-sætninger...og hmm på en eller anden måde en mulighed for at fylde data i sql-sætningerne....
Pointen i interfacet var at så kunne DBhandleren i sin konstruktør modtage et objekt af den type (interfacet) Dette objekt indeholdt så på en elleranden måde De SQL-sætninger der skulle bruges i den pågældende applikation. Hvis der skal laves en forspørgsel kaldes så først en funktion på det objekt der indeholder SQL, som færdiggør SQLen...altså dvs. putter de data ind der er blevet hentet fra grænsefladen....Herefter kaldes DBHandler funktioenen...som så udfører SQL-strengen fra vores objekt...Gir det lidt mening?
Nej det er korrekt....Der er heller ikke noget check på om den parameterstreng man sender med faktisk er korrekt.... Ville være rart hvis man kunne fange begge dele compileTime...Men det er jo bare stort set umuligt...
Men okay...så kan man så sige at det jo ikke er anderledes end at syntaksen i en SQL-streng heller ikke kan checkes compile-time...Men gir en exception når den blir fyret af...
På den anden side....Begrænser man sig egentlig ikke fra en masse DB-funktionalitet hvis man kapsler det hele ind i sådan et objekt....Medmindre man vil til at wrappe alle DB-funktioner der er i .net...og det er jo en større affærre.... arrgh, det er jo til at blive sindsyg af det her :D
Undskyld den bratte afslutning, men jeg har lidt for mange løse ender...Blir nødt til at lukke for nogle af alle mine spg. Tak for hjællpen. Hvis der er lagt svar får disse point, eller er jeg nødt til at tage dem selv for at lukke alle de her spg. Mvh.
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.