webForumDet fria alternativet

Kan man koda såhär i C#?

.NET

27 svar · 2 103 visningar · startad av CatZ

Medlem sedan jan. 20022 440 inlägg
Frågan#1

Jag håller på att lär om, lär rätt (har gett mig på C#) och behöver lite synpunkter på en funktion jag konverterat från visual basic.

public OleDbDataReader DbReader(String mySql)
	{
	    OleDbConnection objConn = new OleDbConnection();
	    OleDbCommand objCmd = new OleDbCommand();
	    OleDbDataReader objReader;
	    
	   try
	   {
			objConn = OleDbConnection(objConn);
			objConn.Open();

			objCmd = OleDbCommand(mySql, objConn);
			objCmd.CommandType = CommandType.Text;
			objDataReader = objCmd.ExecuteReader(CommandBehavior.CloseConnection);
			DbReader = objDataReader;
			return DbReader;
		}
		catch(Exception Ex)
		{
			objConn.Close();
			dbReader = Nothing;
		    //LogError(Ex.Message);
		}
	}
Medlem sedan aug. 20039 340 inlägg
#2

Jag är väl ingen hejare på C#, men så här tänker jag.
Sista två raderna ska du ersätta med bara return objDataReader;
VB's sätt att returnera saker funkar inte alls i C# (Iofs har jag inte prövat, men det vore dumt isf)
Vad gäller felhanteringentycker jag att du bör ta bort den helt ur denna funktion. OM det nu faktiskt sker ett fel bör det faktiskt kastas bör du ju se det så att du kan korrigera det, inte att felet bara ignoreras. Ev behöver du ändra funktionsdefinitionen till
public OleDbDataReader DbReader(String mySql) throws Exception
för att kunna ta bort try...catch.

Medlem sedan jan. 20022 440 inlägg
#3
public OleDbDataReader DbReader(String mySql)
{
	OleDbConnection objConn = new OleDbConnection();
	OleDbCommand objCmd = new OleDbCommand();
	OleDbDataReader objReader;
	
   try
   {
		objConn = OleDbConnection(objConn);
		objConn.Open();

		objCmd = OleDbCommand(mySql, objConn);
		objCmd.CommandType = CommandType.Text;
		objDataReader = objCmd.ExecuteReader(CommandBehavior.CloseConnection);
		return objReader;
	}
	catch(Exception Ex)
	{
		objConn.Close();
		objReader = Nothing;
		//LogError(Ex.Message);
	}
}

Förstår inte alls vad du menar gällande felhanteringen tyvärr.

Medlem sedan sep. 200278 inlägg
#4

Personligen skulle jag inte returnera något inne i ett try-catch-block. Dessutom är det bra om du stänger din connection i metoden, förslagsvis i finally { ... }

public OleDbDataReader DbReader(String mySql)
	{
	    OleDbConnection objConn = new OleDbConnection();
	    OleDbCommand objCmd = new OleDbCommand(mySql, objConn);
	    objCmd.CommandType = CommandType.Text;
	    OleDbDataReader objReader;
	    
	   try
	   {
			objConn.Open();
			objReader = objCmd.ExecuteReader(CommandBehavior.CloseConnection);
// Inte returnera inne i try { .. }

		}
		catch(Exception Ex)
		{
			dbReader = Nothing;
		    //LogError(Ex.Message);
                        // Här skulle jag kasta om felet 
			throw new Exception(ex);
		}
		finally // Körs oavsett om ett fel uppstår, eller ej.
		{
			// Stäng databasanslutningen om den är öppen.
			if (objConn.State == ConnectionState.Open)
				objConn.Close(); //Stäng anslutningen
		}
		// Returnera readerobjektet
		return objReader;
	}

Jag har inte testat koden, bara psuedokod, typ.

Medlem sedan juli 20011 304 inlägg
#5

Det stämmer att man ofta stänger en datareader eller connection (båda i detta fallet) i ett finally block. Jag skulle göra som nitro2k01, men om man vill returnera den kan det tyckas märkligt att sedan returnera en stängd datareader. Det nitro2k01 menar med felhanteringen är att den som ropar på din funktion aldrig får reda på om det gick åt skogen, det enda som görs är loggingen. Din funktion kommer då inte att returnera någonting (den borde därför inte ens gå att kompilera) vilket kommer att generera ett annat (typ av) fel.

Det måste alltså vara upp till den som ropar på funktionen att stänga datareadern. Jag gör oftast inte på detta vis då det bäddar för fel och att man inte har kontroll över om den stängs eller inte. Men det kan vara befogat om en annan funktion använder funktionen som hjälp istället för att öppna en reader från scratch eller så.

Men som sagt: ta en funderare på om du är säker på att du vill skicka runt öppna datareaders hur som helst.

Vad det gäller själva koden ser den lite skum ut:
* Jag antar att OleDbConnection(objConn); och OleDbCommand(mySql, objConn); är anrop till andra funktioner. Lite otydliga namn i så fall ;)
* OM det är så att OleDbConnection och OleDbCommand returnerar objekt som du använder är det onödigt att skapa new på dom lite högre upp, de referenserna sätts ju om omgående.
* Du ska inte sätta DbReader till din datareader, det räcker med att returnera den.
* Varför skickar objConn med sig själv till OleDbConnection?
* Skicka vidare exception i din catch efter loggingen.

Försök att göra om den lite så ska vi hjälpa dig att få till det rätt :)

Medlem sedan nov. 200614 inlägg
#6

Detta kanske inte är det bästa sättet men så brukar jag göra i SQL SERVER:

lägg ConnectionString i web.config

t.ex

<connectionStrings>
    <add name="NorthwindConnectionString" 
         connectionString="Data Source="din server";Initial Catalog="databas"; Integrated Security=True; Min Pool Size=20" 
         providerName="System.Data.SqlClient"/>
  </connectionStrings>

Skapa särskild klass för connection till DB

t.ex:

public class ConnectionManager
{

    public static SqlConnection GetNorthwindConnection()
    {
        // Hämta COnnectionString från web.config
        string connectionString = ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString;

        //Skapa DB Connection
        SqlConnection connection = new SqlConnection(connectionString);

        // Öppna Connection och return det
        connection.Open();
        return connection;
    }

}

Sedan skapar jag egna klasser och metoder för DataAccess

t.ex

public static SqlDataReader GetProducts()
    {
        string sql = "SELECT * FROM Products";

       //Använder SQL connection från min Connection klass
        SqlConnection connection = ConnectionManager.GetNorthwindConnection();

       //Skapar Command object
        SqlCommand command = new SqlCommand(sql, connection);
        command.CommandType = CommandType.Text;

        //Fyller DataReader med data
        SqlDataReader reader = command.ExecuteReader(CommandBehavior.SingleResult | CommandBehavior.CloseConnection);
        return reader;
    }

om du använder VS 2005 använder Du ObjectDataSource för att hämta resultatet till din aspx fil.

Medlem sedan juni 20008 205 inlägg
#7

Det som heter Nothing i VB heter null i C#.

Medlem sedan feb. 2005280 inlägg
#8

Jag skulle returnerat en DataTable istället, och stänga alla db conns så snabbt som möjligt.

Då kan man även passa på att slänga in en .net cache om önskvärt på ett enkelt sätt

Medlem sedan aug. 20003 575 inlägg
#9

freguz skrev:

Jag skulle returnerat en DataTable istället, och stänga alla db conns så snabbt som möjligt.

Då kan man även passa på att slänga in en .net cache om önskvärt på ett enkelt sätt

Det beror ju förstås på ändamålet, det som han kanske vill göra sedan är att kopiera över det i en objektstruktur, det går ju minst lika bra om inte bättre :).

Medlem sedan feb. 2005280 inlägg
#10

Nickemannen skrev:

Det beror ju förstås på ändamålet, det som han kanske vill göra sedan är att kopiera över det i en objektstruktur, det går ju minst lika bra om inte bättre :).

Det är kanske sant. Vet inte riktigt vad som inte skulle gå att göra med DataTable. Vore trevligt med lite mer info om hur detta ska användas, dvs vart tar objDataReadern vägen :birp

Medlem sedan aug. 20003 575 inlägg
#11

freguz skrev:

Det är kanske sant. Vet inte riktigt vad som inte skulle gå att göra med DataTable. Vore trevligt med lite mer info om hur detta ska användas, dvs vart tar objDataReadern vägen :birp

Man kan nog göra lika mycket med en DataTable som man kan med en objektmodell, dock så kan det diskuteras hur "bra" koden blir. (beror ju helt och hållet på smak och hur duktig utvecklaren är på sin sak). Valet mellan DataTable tänkandet och objektmodell har ju också med kraven på applikationen att göra.

Det finns flera artiklar både för och emot DataTable's så jag tänker inte gå in på vad som är bäst.

http://www.designpatternsfor.net/default.aspx?pid=22 här är ett exempel på hur det kan fungera (inte världens snyggaste kod men det ger ju en ide om hur man kan arbeta med en datareader).

Det finns även flera färdiga ramverk som man kan använda sig där man har en hel del funktionalitet färdigt för detta. bl.a. NHibernate som jag rekommenderar starkt.

Medlem sedan maj 20012 812 inlägg
#12

nickemannen skrev:

Det beror ju förstås på ändamålet, det som han kanske vill göra sedan är att kopiera över det i en objektstruktur, det går ju minst lika bra om inte bättre .

Generellt så är det bättre ur skalbarhet att returnera DataTable än en dataReader eftersom man stänger databaskopplingen tidigare. Ju mer kod som man exekverar innan man är färdig med sin datareader, destu bättre blir det med DataTable.

Framför allt så skulle jag använda en DataTable eftersom jag inte riktigt gillar tanken på man stänger databaskopplingen någonstans i koden där "logiken" inte hör hemma. Speciellt viktigt blir det om man bygger ett DAL som andra kan använda sig av, som kanske inte riktigt förstår vikten av att stänga datareader så tidigt som möjligt.

- M

Medlem sedan aug. 20003 575 inlägg
#13

Gladh skrev:

nickemannen skrev:

Det beror ju förstås på ändamålet, det som han kanske vill göra sedan är att kopiera över det i en objektstruktur, det går ju minst lika bra om inte bättre .

Generellt så är det bättre ur skalbarhet att returnera DataTable än en dataReader eftersom man stänger databaskopplingen tidigare. Ju mer kod som man exekverar innan man är färdig med sin datareader, desto bättre blir det med DataTable.

Framför allt så skulle jag använda en DataTable eftersom jag inte riktigt gillar tanken på man stänger databaskopplingen någonstans i koden där "logiken" inte hör hemma. Speciellt viktigt blir det om man bygger ett DAL som andra kan använda sig av, som kanske inte riktigt förstår vikten av att stänga datareader så tidigt som möjligt.

- M

Håller med att man enklare kan stänga kopplingen om man retunerar en DataTable istället för en Reader, men det beror ju helt och hållet på vad man anser att sitt DAL är.

Ditt dal kan ju innehålla IList<Customer> UserDAL.GetCustomers() i det fallet så behöver dom andra ändå inte tänka på att readern överhuvudtaget.

Skapar man en Factory där man har en Create metod som retunerar en Customer eller IList<Customer> som tar emot en reader och låter Factoryn allt id stänga readern så har man en generell och konsekvent lösning.

Jag tycker nog inte att det är några problem att man exponerar en DataReader för andra klasser, det beror helt på vilken arkitektur man vill ha.

Rent exekveringstidsmässigt behöver ju inte databaskopplingen stängas senare.

Men visst det kan leda till fler felkällor osv, men som sagt det är en smaksak på vad man vill köra med, i större projekt tycker jag personligen att användade av DataTable's gör utvecklandet mer komplext och mer svårunderhållbar (samt att man lätt går ifrån OOPtänket tycker jag) kod än med en objektmodell.

Medlem sedan maj 20012 812 inlägg
#14

nickemannen skrev:

Ditt dal kan ju innehålla IList<Customer> UserDAL.GetCustomers() i det fallet så behöver dom andra ändå inte tänka på att readern överhuvudtaget.

mmmmm... med det resonemanget så behöver vi ju knappast bry oss om man returnera DataTable eller DataReader, eller hur? Vilket vi diskuterade.

nickemannen skrev:

Skapar man en Factory där man har en Create metod som retunerar en Customer eller IList<Customer> som tar emot en reader och låter Factoryn allt id stänga readern så har man en generell och konsekvent lösning.

Här har du full koll på användandet av din datareader och du bör ju ha koll på att du skall stänga din datareader efter dig. Generellt är det dock en sämre lösning att använda sig av datareader för att skapa dina object än en datatable, eftersom du håller din koppling till databasen öppen längre, samt att du kan få exceptions i kod som inte är direkt relaterade till din datareader vilket gör att man lätt glömmer att stänga datareadern här när felet kastas...

nickemannen skrev:

Jag tycker nog inte att det är några problem att man exponerar en DataReader för andra klasser, det beror helt på vilken arkitektur man vill ha.

Jag är av en annan åsikt, det är det som är det härliga med kodningen det finns ingen absolut sanning.

nickemannen skrev:

Rent exekveringstidsmässigt behöver ju inte databaskopplingen stängas senare.

Det får du gärna utveckla för jag 1) förstår inte hur detta är möligt 2) förstår inte hur du tänker här.

nickemannen skrev:

Men visst det kan leda till fler felkällor osv, men som sagt det är en smaksak på vad man vill köra med, i större projekt tycker jag personligen att användade av DataTable's gör utvecklandet mer komplext och mer svårunderhållbar (samt att man lätt går ifrån OOPtänket tycker jag) kod än med en objektmodell.

Nu är det ju knappast så att vi diskuterat DataTables vs Object. Utan mer dataReaders vs DataTables. Jag använder mig alltid av Objektmodell/entiteter i mina projekt, men har alltid en DataTable när jag skapar mina objekt/listor av objekt istället för en datareader.

- M

Medlem sedan aug. 20003 575 inlägg
#15

mmmmm... med det resonemanget så behöver vi ju knappast bry oss om man returnera DataTable eller DataReader, eller hur? Vilket vi diskuterade.

Du har rätt jag gick nog ifrån ämnet lite.

Det får du gärna utveckla för jag 1) förstår inte hur detta är möligt 2) förstår inte hur du tänker här.

När det gäller tidsmässigt som jag pratade om så använder ju sig DataTable'n sig själv av en DataReader och beroende på hur optimerat du bygger din mappning av data så kan den ju bli snabbare än hur en DataTable läser in sin data. Vid en typad datatable kan det nog gå riktigt snabbt, däremot är det en icketypad datatable så kan det nog ta lite längre tid att fylla din datatable gentemot fylla objekt, därav ser jag att man kan få sin datareader stängd lika fort eller till och med fortare.

Medlem sedan maj 20012 812 inlägg
#16

nickemannen skrev:

När det gäller tidsmässigt som jag pratade om så använder ju sig DataTable'n sig själv av en DataReader och beroende på hur optimerat du bygger din mappning av data så kan den ju bli snabbare än hur en DataTable läser in sin data. Vid en typad datatable kan det nog gå riktigt snabbt, däremot är det en icketypad datatable så kan det nog ta lite längre tid att fylla din datatable gentemot fylla objekt, därav ser jag att man kan få sin datareader stängd lika fort eller till och med fortare.

Vid ett "otypat datatable" så skapas det en del collections som datan läggs ner i.

Typade datatable har jag aldrig ens hört talas om :) men om det finns misstänker jag att det är som ett typat dataset, det villsäga en klass med ett otypat dataset under sig som man anropar vid varje förfrågning av data och det görs en unbox/box vid varje förfrågning till datasetet, att fylla det med data tar dock inte längre tid än ett vanligt otypat dataset eftersom det är det som ligger i botten.

Jag har svårt att se hur det skulle gå fortare att fylla objekt med data jämfört med datatablen, eftersom om du vill fylla objektet så måste du använda dig av reflection (långsamt) för att hitta rätt medlemsvariabler som skall ha datan, du måste också igenom något sorts mappningsförfarande (vilket du slipper med datatablen). Dessutom så kan det finnas event kopplade till dessa, säg att du skapar ett objekt i din ORMapper och när det är gjort så skapar ORMappern ett ObjektCreated-event som du kan lyssna på och göra olika saker med.
Om du då har en datareader så är den fortfarande öppen när eventet skapas, medans med en datatable så är kopplingen stängd. Och du som skapar av ORMappern har ingen som helst anning om vad som sker i koden som lyssnar på eventet...

Nu har jag inte sett några som helst mättningar på detta, men då jag byggt ett par små ORMapper, samt kollat lite på DataTable koden, så kan jag säga att jag inte skulle klara av att optimera min kod så att jag skulle kunna fylla mina listor med skapade objekt snabbare än vad det tar för MS att fylla sitt DataTable. Men det är ju bara jag, du är helt enkelt en bättre programmerare än jag i detta fallet. Vilket ju är asbra eftersom du så fall har sparat in ett moment: data -> datareader -> objekt, medans jag gör: data -> datareader -> datatable -> objekt.

- M

Medlem sedan aug. 20003 575 inlägg
#17

Gladh skrev:

nickemannen skrev:

När det gäller tidsmässigt som jag pratade om så använder ju sig DataTable'n sig själv av en DataReader och beroende på hur optimerat du bygger din mappning av data så kan den ju bli snabbare än hur en DataTable läser in sin data. Vid en typad datatable kan det nog gå riktigt snabbt, däremot är det en icketypad datatable så kan det nog ta lite längre tid att fylla din datatable gentemot fylla objekt, därav ser jag att man kan få sin datareader stängd lika fort eller till och med fortare.

Vid ett "otypat datatable" så skapas det en del collections som datan läggs ner i.

Typade datatable har jag aldrig ens hört talas om :) men om det finns misstänker jag att det är som ett typat dataset, det villsäga en klass med ett otypat dataset under sig som man anropar vid varje förfrågning av data och det görs en unbox/box vid varje förfrågning till datasetet, att fylla det med data tar dock inte längre tid än ett vanligt otypat dataset eftersom det är det som ligger i botten.

Jag har svårt att se hur det skulle gå fortare att fylla objekt med data jämfört med datatablen, eftersom om du vill fylla objektet så måste du använda dig av reflection (långsamt) för att hitta rätt medlemsvariabler som skall ha datan, du måste också igenom något sorts mappningsförfarande (vilket du slipper med datatablen). Dessutom så kan det finnas event kopplade till dessa, säg att du skapar ett objekt i din ORMapper och när det är gjort så skapar ORMappern ett ObjektCreated-event som du kan lyssna på och göra olika saker med.
Om du då har en datareader så är den fortfarande öppen när eventet skapas, medans med en datatable så är kopplingen stängd. Och du som skapar av ORMappern har ingen som helst anning om vad som sker i koden som lyssnar på eventet...

Nu har jag inte sett några som helst mättningar på detta, men då jag byggt ett par små ORMapper, samt kollat lite på DataTable koden, så kan jag säga att jag inte skulle klara av att optimera min kod så att jag skulle kunna fylla mina listor med skapade objekt snabbare än vad det tar för MS att fylla sitt DataTable. Men det är ju bara jag, du är helt enkelt en bättre programmerare än jag i detta fallet. Vilket ju är asbra eftersom du så fall har sparat in ett moment: data -> datareader -> objekt, medans jag gör: data -> datareader -> datatable -> objekt.

- M

Typat dataset ja det stämmer.

Hmmm, jag menade i detta fallet utan en ORMapper, utan syftade mer på skriven mappning eller genererad kod vilket jag tror går snabbare, har för mig jag sett mätningar också som visar detta.

Dock har det inte med diskussionen som vi kommit utanför nu :|.. Men jag skulle iallfall säga att användandet av en DataReader behöver inte alls betyda att databaskopplingen stängs senare. Sedan har det upp till utvecklaren hur skickling han är på att hantera detta.

Om man lyssnar på object created event så om man är skicklig så triggar man inte detta under inläsningen.

Jag säger inte att man skall välja en DataReader före DataTables/DataSets för att den är snabbare. För även om den är snabbare så märks det knappt av slutanvändaren ändå, utan att man skall inte välja bort den för att man tror att den är långsammare för det är den absolut inte när den används korrekt.

Medlem sedan maj 20012 812 inlägg
#18

nickemannen skrev:

För även om den är snabbare så märks det knappt av slutanvändaren ändå, utan att man skall inte välja bort den för att man tror att den är långsammare för det är den absolut inte när den används korrekt.

DataReader kan aldrig vara långsammare än en datatable, eftersom det är precis som du sagt tidigare att datatablen använder sig av datareadern för att fylla sig med data. Problemet med datareadern är ju att den måste hålla en koppling öppen till databasen så länge som man hämtar data från den, vilket gör att det inte är ett så bra val om man inte har riktigt kontroll över när och hur den används.

nickemannen skrev:

Hmmm, jag menade i detta fallet utan en ORMapper, utan syftade mer på skriven mappning eller genererad kod vilket jag tror går snabbare, har för mig jag sett mätningar också som visar detta.

Om du menar att man skriver specifik kod för varje object så kommer det givetviss öka upp hastigheten för att skapa objekten. Men fy vilket slavjobb.... nej då är ORMappern att rekomender alla dagar i veckan, eller möjligtviss någon generator som genererar kod utifrån databas och dina objekt.

- M

Medlem sedan jan. 20022 440 inlägg
#19

Jag har iofs inte varit särskilt noga med att bygga upp strukturen på det viset som ni menar. Jag har två olika funktioner för att returnera data som ser i princip lika ut fast den ena returnerar ett datatable och den andra returnerar en datareader har inte tagit någon hänsyn till något annat än min lathet.

Om jag vill koda med OOP i tankarna hur ska jag då bygga upp dataåtkomsten? Var kan jag lära mig mer om C#? Boken jag har är bra men det är exempel som jag inte riktigt kan applicera på det projekt jag tänkt ta mig an nu.

Medlem sedan aug. 20003 575 inlägg
#20

CatZ skrev:

Jag har iofs inte varit särskilt noga med att bygga upp strukturen på det viset som ni menar. Jag har två olika funktioner för att returnera data som ser i princip lika ut fast den ena returnerar ett datatable och den andra returnerar en datareader har inte tagit någon hänsyn till något annat än min lathet.

Om jag vill koda med OOP i tankarna hur ska jag då bygga upp dataåtkomsten? Var kan jag lära mig mer om C#? Boken jag har är bra men det är exempel som jag inte riktigt kan applicera på det projekt jag tänkt ta mig an nu.

Jag tycker du skall ta dig en titt på NHibernate eller NPersist.

290 ms totalt · 4 externa anrop · v20260731065814-full.a51de22e
136 ms — deklarationer (db)
0 ms — hämta statistik (cache)
152 ms — hämta tråd, inlägg och bilagor (db)
133 ms — ändringar (db)