webForumDet fria alternativet

Problem med datareader - requires an open and available Connection

.NET

11 svar · 342 visningar · startad av Jon

Medlem sedan juli 20011 304 inlägg
Frågan#1

Min applikation krashar ibland med felmeddelandet:

ExecuteReader requires an open and available Connection. The connections current state is Closed

Mitt DAL består av en singelton som Delar ut connections ungefär så här:

// I DAL - abstrakt klass
IDbConnection	conn       = null;
public IDbConnection Connection
{
    get 
    { 
        if (conn == null)
        {
	conn = GetConnection();
        }
        
        return conn;   
     }
}

// I SqlServerDal : DAL
public override IDbConnection GetConnection()
{
    SqlConnection newConn = new SqlConnection(ConnectionString);
    newConn.Open();
    return newConn;			
}

Har försökt att lägga till:

else if(conn.State == ConnectionState.Closed)
{
    conn = GetConnection();
}

Men det gör ingen skillnad.
Situationen verkar uppstå när det är många användare som använder applikationen samtidigt.

Någon som ser ngot uppenbart fel?

Medlem sedan apr. 20012 266 inlägg
#2

Det jag kan tänka mig är att den är static på något sätt vilket gör att alla användare använder samma connection och därför blir det problem för en användare då anslutningen är stängd av en annan. Dock ser jag inte det problemet just i din kod. Får sova på saken :) Natt!

Medlem sedan juli 20011 304 inlägg
#3

Jo jag är inne på samma linje. TYcker att jag stänger den ordentligt överallt. Hmm...

Kan det vara så att om man avbryter den mitt i en operation, dvs ändrar sig när data hämtas och helt plötsligt klickar på en länk nånstans så blir det knas?

Medlem sedan apr. 20012 266 inlägg
#4

Jon skrev:

Jo jag är inne på samma linje. TYcker att jag stänger den ordentligt överallt. Hmm...

Det är väl just det som är problemet i fall samma connection används för alla användare, då den stängs av andra användare och inte öppnas igen. Hade samma problem när jag körde den som static utan att tänka på detta.

Medlem sedan juli 20011 304 inlägg
#5

Där har du ju en poäng! :)

Men jag vill ha den statisk. Undrar om man kanske kan kolla om den är öppen innan man stänger den. Fast då kan den kanske bli hängandes öppen. Knepigt!

Medlem sedan apr. 20012 266 inlägg
#6

Tror inte att du direkt tjänar något på att ha den statisk då .NET ändå använder sig av connection pool för att slippa ner och uppkopplingar till databasen. Annars om du fortfarande vill ha en statisk får du lov att göra någon form av kö-system så att saker inte körs samtidigt.

Medlem sedan juli 20011 304 inlägg
#7

Kanke det men om jag ändrar så att den returnerar en ny connection varhe gång så får jag:

Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached

Medlem sedan maj 20012 812 inlägg
#8

Varför i all världen vill du hämta en connection från ditt DAL och använda någon annanstans?

Dit DAL skall hantera allt som har med Databasen att göra och dina övriga lager skall absolut INTE kunna komma åt din connection.

Ditt DAL skall göra följande:

1. Ta emot data/SQL sträng.
2. Öppna en connection mot en databas
3. Processa datan/SQL strängen
4. Stänga connection till databasen
5. Returnerar eventuella resultat.

Här är din connection fint inkappslad i ditt DAL och dina övriga lager behöver aldrig bry sig om var/hur/och varför din data lagras.

Säg att du helt plötslig (av någon outgrundlig anledning) bestämmer dig för att inte spara i en databas utan du vill skicka iväg datan som ett mail istället (eller mer troligt stoppa det på en kö och låta en central COM+ komponent sköta all databashantering) då får du skriva om massor av din kod om du skickar tillbaka ett IConnection objekt som dina andra lager använder, eftersom den ny inte är till någon som helst nytta när datan skall skickas som ett mail.

Så ändra ditt DAL så det fungerar som ovanstående. Jag skulle sedan rekomenderar dig att ditt DAL returnerar ett DataTable och möjligtvis en DataReader, men de har den fula egenskapen att de håller databaskopplingen öppen så länge de själva är öppna, så då måste man sätta commandBehaivor på datareader samt vara nog med att de stängs annars så tappar du en massa databaskopplingar.

- M

Medlem sedan juli 20011 304 inlägg
#9

Jag har inte varit så tydlig i resten av funktionaliteten, men jag har en objectbroker (som är den enda som pratar med mitt DAL) Den får datareaders och fyller på BusinessObjects som returneras till applikationen.

Mitt DAL i övrigt fungerar exakt som du beskriver i punkterna.

Tror att jag har hittat felet - det har att göra med när min connection stängs och commandBehaivor på datareadern, alltså punkt 4 men tack för feedback ändå. :)

Medlem sedan maj 20012 812 inlägg
#10

Nu vet jag inte hur din objectbroker fungerar. Men jag skulle nog rekomenderar dig att använda en DataTable ändå. Det gör jag i min ORMapper.

Funderade på DataReaders först, men kom på att så fort man skall börja fylla sin collection av objekt med data så håller man kopplingen öppen längre tid än nödvändigt eftersom man gör förfrågningar på dels metadatan och det objekt som man skall fylla. Så jag returenerar en DataTable istället för en DataReader eftersom jag då får den inkapsling som jag eftersträvar.

Samt att jag faktiskt har möjligheten att manuellet skapa och fylla en DataTable, vilket jag inte har med en DataReader om jag nu måste ha någon annan källa än en databas.

Där finns en prestandavinst i att använda DataReadern, men då man ändå har större prestandförluster i att använda reflection för att fylla sina objekt, så är vinsterna större med att returnerar ett DataTable än en DataReader, då man får ett mer skalerbart system.

Målet är att alltid inkapsla sina lager så mycket som möjlighet så att det övrelagret har en referens till det undre, men det undre aldrig är beroende av det övre, vilket du får här när ditt DAL är beroende av att din ORMapper stänger kopplingen för dig.

Det är dock din kod och du gör som du finner bäst för dig :)

- M

Medlem sedan juli 20011 304 inlägg
#11

Det är dock din kod och du gör som du finner bäst för dig

Jajjamensan, men det är alltid värdefullt med andras åsikter och insikter. Kanske testar med datatables och benchmarkar lite när jag får tid. :)

Medlem sedan juli 20011 304 inlägg
#12

Återkommer med lite feedback:

Det blev märkbart långsammare med datatables än datareaders. Jag använda ganska stora datamängder, ca: 1500 objekt med kanske 10-20 relaterade objekt var.

Nu optimerade jag inte inhämtningen förstås, men men ...

266 ms totalt · 3 externa anrop · v20260731065814-full.767b4345
131 ms — deklarationer (db)
0 ms — hämta statistik (cache)
132 ms — hämta tråd, inlägg och bilagor (db)