hur gör man en delete i en loop?
Dim myConnection As New SqlConnection()
myConnection.ConnectionString = "user id=xxx;password=3xxx;initial catalog=xxx;data source=xxx;Connect Timeout=10"
Dim mySelect As New SqlCommand("viewBulkMail", myConnection)
mySelect.CommandType = CommandType.StoredProcedure
mySelect.Connection.Open()
Dim myReader As SqlDataReader = mySelect.ExecuteReader(CommandBehavior.CloseConnection)
Dim intMsgId As Int32
Dim strDestination As String
Dim strSource As String
Dim strSubject As String
Dim strBody As String
Dim mm As New MailMessage()
While myReader.Read()
intMsgId = myReader.GetValue(0)
strDestination = myReader.GetValue(1)
strSource = myReader.GetValue(2)
strSubject = myReader.GetValue(3)
strBody = Replace(myReader.GetValue(4), vbCrLf, "<br>")
Try
mm.BodyFormat = MailFormat.Html
mm.From = strSource
mm.To = strDestination
mm.Subject = strSubject
mm.Body = strBody
SmtpMail.SmtpServer = "xxx"
SmtpMail.Send(mm)
'raderar alla skickade meddelanden
Dim myDelete As New SqlCommand("deleteBulkMail", myConnection)
myDelete.CommandType = CommandType.StoredProcedure
myDelete.Parameters.Add("@IDno", SqlDbType.VarChar).Value() = intMsgId
myDelete.Connection.Open()
myDelete.ExecuteNonQuery()
myDelete = Nothing
Catch
'uppdaterar status på alla error meddelanden
Dim myUpdate As New SqlCommand("updateBulkMail", myConnection)
myUpdate.CommandType = CommandType.StoredProcedure
myUpdate.Parameters.Add("@IDno", SqlDbType.VarChar).Value() = intMsgId
myUpdate.Connection.Open()
myUpdate.ExecuteNonQuery()
myUpdate = Nothing
End Try
End While
felkod:
The connection is already Open (state=Open).
Kommenterar jag bort raden:
myDelete.Connection.Open() så får jag felet:
There is already an open DataReader associated with this Connection which must be closed first.
Ska man använda en annan sorts loop istället för en reader?
GladhMedlem sedan maj 20012 812 inlägg Om du vill göra som du försöker så måste du öppna en ny connection vid varje delete operation.
Jag skulle dock inte göra så du gör av 2 skäl.
1. Du kommer garanterart får problem med låsningar när du försöker deletea en post i databasen, när en annan connection håller på att läsa den. Typiskt Deadlock problem.
2. Det är extremt obra att göra något som tar lite längre tid i en readerloop. Och detta beror på att du håller din koppling öppen till databasen så länge din reader är öppen.
Så Om du vill göra något som du vill så hade jag löst det genom att hämta all data in i en DataTable eller DataSet och sedan skickat iväg alla mail, och när ett mail skickats så hade jag deletet dens post i databasen. Sedan hade jag även funderat på att implementerar trådning, eftersom det kan ta ett litet tag att koppla sig till smtp-server och skicka iväg mailet, om du då har många mail som skall skickas iväg så kan det vara bra att skicka typ 5 åtgången parallet, istället för att skicka de seriellt som du gör i en loop.
aha, då är det trådning som gäller eftersom det kommer att kunna vara många mail som skickas!
då ska man bara lista ut hur det funkar! :)
har du nått trådexempel får du gärna posta det! :)
GladhMedlem sedan maj 20012 812 inlägg Det är lite svårt att förstå bara så där med kodexempel, och eftersom det är olika många mail varje gång, så är det bästa nog att använda .NET's trådpool.
Läs på mer om threads på MSDN eller på någon site, sök på thread C# programming på google och du får massor med träffar. Man måste förstå konceptet med trådhantering, så man gör sin kod threadsafe, alltså att 2 trådar inte kan ändra en och samma variabel samtidigt, detta brukar generera lite lustiga fel, som man oftast inte upptäcker förrens i produktion och som dessutom är jobbiga att hitta, så ett kodexempel hjälper inte så mycket om man inte har all kunskap.
Sedan om det är riktigt mångmail som skall skickas och det är ofta som mailen skall skickas så hade jag lyft ut den funktionallitet från ASP.NET till en WindowsServices som legat och skickat iväg delmängder av mailen med jämnamellan rum, säg att den skickar iväg 100 mail varje kvart, det ger ett jämnare uttnyttjande av prestanda och "sänker" inte maskinen när du vill skicka iväg tusentals mail på en gång.
- M
Gladh skrev:
lyft ut den funktionallitet från ASP.NET till en WindowsServices
va bra, för det är precis vad det är.
koden är hämtad ifrån min windows service! :)
ang. trådar:
ushh, synd att det är sååå tråkigt att behöva lära sig nya saker hela tiden när man ska göra nånting! :(
men men, det är väl bara att bita i det sura.
GladhMedlem sedan maj 20012 812 inlägg
Gladh skrev:
--------------------------------------------------------------------------------
lyft ut den funktionallitet från ASP.NET till en WindowsServices
--------------------------------------------------------------------------------
va bra, för det är precis vad det är.
koden är hämtad ifrån min windows service!
Bara jag som är knäpp, fick för mig att jag var i ASP.NET forumet. :(
NöffMedlem sedan nov. 2003569 inlägg
och när ett mail skickats så hade jag deletet dens post i databasen
Är det inte bättre att han delete:ar och updaterar allt i en batch när allt är klart istället. Jag tror inte det finns någon begränsning i hur många Querys man kan köra samtidigt i en batch, går säkert att batcha upp ett par tusen delete:s/updates.
string ALL;
for(int u=0;u<DataTable.Rows.Count;u++)
{
try
{
// Gör och skicka mail
ALL+="DELETE FROM konto WITH (TABLOCKX) WHERE kontonr=" + ID + ";";
}catch {
ALL+="UPDATE konto WITH (TABLOCKX) SET error='det gick åt skogen' WHERE ID=" + ID + ";";
}
}
Command.CommandText=ALL;
Command.ExecuteNonQuery();
GladhMedlem sedan maj 20012 812 inlägg
Är det inte bättre att han delete:ar och updaterar allt i en batch när allt är klart istället
Det är mycket möjligt, allt beror på hur viktigt det är att man får korrekt information om vilka mail som har gått iväg och hur viktigt det är att samma mail inte går ut mer än en gång.
Med ett batch jobb så riskerar du att få fler och större problem med "datariktighet" (nytt fint ord jag hittade på) och ju större batch mängden är, destu större problem.
Fast batchjobb är bättre ur prestanda synpunkt även om jag inte skulle löst det så som du har gjort utan istället bara sparat undan ID och kört en SQL sats med en IN() operator i.
Gladh skrev:
Fast batchjobb är bättre ur prestanda synpunkt även om jag inte skulle löst det så som du har gjort utan istället bara sparat undan ID och kört en SQL sats med en IN() operator i.
Så gör jag faktiskt nu, jag bygger ihop alla id:s till två strängar och skickar in i databasen för radering eller uppdatering. (har inte orkat kika på trådning än!) :)
While myReader.Read()
intMsgId = myReader.GetValue(0)
strDestination = myReader.GetValue(1)
strSource = myReader.GetValue(2)
strSubject = myReader.GetValue(3)
strBody = Replace(myReader.GetValue(4), vbCrLf, "<br>")
Try
mm.BodyFormat = MailFormat.Html
mm.From = strSource
mm.To = strDestination
mm.Subject = strSubject
mm.Body = strBody
SmtpMail.SmtpServer = "xxx"
SmtpMail.Send(mm)
strSentMsgId = strSentMsgId & intMsgId & ","
Catch
strRetryMsgId = strRetryMsgId & intMsgId & ","
End Try
End While
'raderar alla skickade meddelanden
If Len(strSentMsgId) > 0 Then
Dim myDelete As New SqlCommand("deleteBulkMail", myConnection)
myDelete.CommandType = CommandType.StoredProcedure
myDelete.Parameters.Add("@IDno", SqlDbType.VarChar).Value() = strSentMsgId
myDelete.Connection.Open()
myDelete.ExecuteNonQuery()
myDelete = Nothing
End If
'uppdaterar alla error meddelanden
If Len(strRetryMsgId) > 0 Then
Dim myUpdate As New SqlCommand("updateBulkMail", myConnection)
myUpdate.CommandType = CommandType.StoredProcedure
myUpdate.Parameters.Add("@IDno", SqlDbType.VarChar).Value() = strRetryMsgId
myUpdate.Connection.Open()
myUpdate.ExecuteNonQuery()
myUpdate = Nothing
End If