Jag försöker att vara smart i min applikation. Här finns bl a tre knappar för uppdatera ny och delite. Hej, Tack Hultan, men jag tror inte att jag förstår riktigt. Hej igen, Du är ju en ängel, men tyvärr. Jag missar väll någonting, eller har glömt visa dig. Det är verkligen inte min dag idag. Jag läste fel på OleDB och ODBC. Men det finns (minst) tre olika namespace för dataaccess (OleDb, Odbc samt Sql) och de är mer eller mindre ekvivalenta (men kopplar mot olika datakällor). Tack, det verkar som om vi är på god väg, men jag har ett lustigt felmedelande som jag inte kan räkna ut. Hmm...Det finns inga default properties i C# (och inte heller i VB.Net om jag minns rätt), vilket innebär att när du skriver t ex textBoxFirma (inne i en strängkonkatenering (strängsammansättning)) så betraktas det som objektet (eller textboxen) textBoxFirma och inte automatiskt propertyn Text på objektet. I VB6 som hade default properties så fick du automatiskt Text-propertyns värde, men så fungerar det inte i .Net av olika skäl. Misstänker att du har utvecklat i VB6? Jag gjorde en SQL-sträng, som ser ut likadant som uppdatesträngen, men det finns inga fel där. Line 1 säger den eftersom SQL-satsen inte innehåller några chr(13) eller chr(10) eller andra radbrytkombinationer. Hela SQL-satsen betraktas alltså som en rad. Det ser ut som en långtradare det här... Aah, jag missade det p g a namnet på listboxen, listBoxTotal. Utan att tänka trodde jag det var numeriskt, dvs totalsumman av någonting...men men...ändringen med ".Text" var också nödvändig so "no harm done"... :-)Uppdate Insert Delete???
Jag har gjort tre variabler (bool) som när man klicka på resp knapp får sitt värde satt till true.
Sedan har jag en gemensam class för att uppdatera databasen:
<code>
if(ny==true)
{
}
if(uppdatera==true)
{
}
if(tabort==true)
{
}
</code>
Innuti klammrarna så har jag olika SQL-strängar för resp och
<code>
OleDbCommand dc = new OleDbCommand(SQL,con);
</code>
(jag fick fel om jag inte har det i varje if-sats).
Därefter kör jag själva uppdateringen:
<code>
try
{
con.Open();
da.Update(ds,"frånKund");
con.Close();
}
catch(Exception fel)
{
MessageBox.Show(fel.Message,"Databasfel");
}
</code>
Vad jag kan läsa fram i min bok så borde ju detta fungera, men jag får ett fel, där den säger:
<code>
Uppdates requires a Valid UppdateCommand when passed DataRow Collection with modifieds Rows
</code>
Jag är inte säker på att jag förstår felmedellandet.
Om det är till hjälp, så är koden bakom knappen uppdatera så här:
<code>
int kund = listBoxTotal.SelectedIndex;
int a = 0;
foreach(string värde in AllaVärden)
{
ds.Tables["frånKund"].Rows[0][a] = värde;
a++;
}
UppdateraDatabasen();
FyllPåTotalt();
listBoxTotal.SelectedIndex = kund;
</code>
Något förslag?Sv: Uppdate Insert Delete???
Felet tror jag kan bero på att när du skapar din DataAdapter (variablen da) så använder du nog konstruktorn som tar en Connection och ett Command-object. Den koden har du iofs inte klippt in, men jag gissar att det är så. Den konstruktorn sätter Command-objektet till SelectCommand-propertyn på DataAdaptern. Det finns en DeleteCommand resp UpdateCommand-property på DataAdaptern som du ska använda vid delete:s samt update:s. Alltså, skriv inte så här :
<code>
OdbcDataAdapter da=new OdbcDataAdapter(dc,con);
</code>
utan i stället för update:s:
<code>
OdbcDataAdapter da=new OdbcDataAdapter(con);
da.UpdateCommand=dc;
</code>
och givetvis på motsvarande sätt för delete:s.
Ett alternativ till din lösning med boolean-variabler är att du alltid skapar alla tre command-objekten och ser till att din dataadapter har tillgång till dessa. Om du gör det så reder dataadaptern ut på vilka rader den ska anropa vilket commandobjekt.
Visserligen får du skapa tre commandobjekt varje gång i st f ett men du slipper en hel del logik i dina knappars event och i updatemetoden som i stället blir generell.
Jag föredrar sistnämnda lösningen i min kod, men gör det som känns rätt för dig...Sv: Uppdate Insert Delete???
Var får jag in min SQL?
Skall jag ha dataadaptern i varje if-sats?
(finns det inte elseif i C#?)
Med tanke på min kod ovan, tror du att du kan/orkar/ha lust med att ge mig ett exempel?
Tack på förhand.Sv: Uppdate Insert Delete???
Glöm mitt svamlande om fel konstruktor, jag tänkte helt fel...får skylla på att jag precis stigit upp :-)
Ungefär så här tänker jag mig :
<code>
public void UpdateDatabase(DataSet ds)
{
OdbcConnection con=new OdbcConnection("connectionstring here");
OdbcCommand mDeleteCommand=new OdbcCommand("delete sql here",con);
OdbcCommand mInsertCommand=new OdbcCommand("insert sql here",con);
OdbcCommand mUpdateCommand=new OdbcCommand("update sql here",con);
OdbcDataAdapter mAdapter=new OdbcDataAdapter();
mAdapter.DeleteCommand=mDeleteCommand;
mAdapter.InsertCommand=mInsertCommand;
mAdapter.UpdateCommand=mUpdateCommand;
mAdapter.Update(ds);
}
</code>
På detta vis behöver du inte bry dig om huruvida de ska ske en update, delete eller insert. Det tar dataadaptern hand om. Du kan till och med uppdatera, radera eller lägga till många rader, så reder dataadaptern ändå ut det åt dig. Då slipper du logiken med booleans för att hålla reda på vilken typ av ändring som har skett.
Hoppas det blev tydligare nu...annars säg till igen så ska jag öppna dagens första Coca-Cola och se om det hjälper att få igång min hjärna :-)Sv: Uppdate Insert Delete???
Jag antar att jag skall visa steg för steg hur jag har det.
<code>
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Data.OleDb;
private OleDbConnection con;
private OleDbDataAdapter da;
private OleDbDataAdapter da1;
private DataSet ds;
private DataSet ds1;
string CONstring = "Provider=sqloledb;Server=sawdata;Database=Melodi;Trusted_Connection=yes";
con = new OleDbConnection(CONstring);
</code>
Här har jag initieringen. Som du ser så använder jag mig av OleDbDataAdapter inte OdbcDataAdapter.
Jag ansluter ju i början(skall göra om det till en egen class sedan, varför ansluta en gång till?
När jag klicka på knappen uppdatera:
<code>
int kund = listBoxTotal.SelectedIndex;
int a = 0;
foreach(string värde in AllaVärden)
{
ds.Tables["frånKund"].Rows[0][a] = värde;
a++;
}
UppdateraDatabasen();
FyllPåTotalt();
listBoxTotal.SelectedIndex = kund;
</code>
Jag börjar att fundera på om jag skall ha dessa koder??
Som du ser så refererar denna kod till UppdateraDatabasen();, men jag får problem med UppdateraDatabasen(DataSet ds);
Efter detta så gäller ju uUppdateraDatabasen!
Istället för OdbcConnection, hur gör jag där???
(kalas att du offrar din tid)Sv: Uppdate Insert Delete???
Byt alltså ut alla mina OdbcCommand mot OleDbCommand o s v (alltså även DataAdaptern samt Connection).
Jag valde att lägga till datasetet som ett argument till funktionen men om du har ditt dataset deklarerat på formulärnivå så går det lika bra att strunta i det. Så ta bort argumentet "DataSet ds".
Eftersom du i din kod har angett tabellnamn ("frånKund") i anropet till Update-metoden så kan det vara lika bra att göra det i min kod också (även om det inte är nödvändigt om man bara har en DataTable i DataSet:et.
Har också döpt om funktionen till samma namn som du använde. (Mitt exempel var inte tänkt att bara klistra in, men det märkte du ju :-)
Då är vi väl framme vid följande kod :
<code>
public void UppdateraDatabasen()
{
try
{
OleDbCommand mDeleteCommand=new OleDbCommand("delete sql",con);
OleDbCommand mInsertCommand=new OleDbCommand("insert sql",con);
OleDbCommand mUpdateCommand=new OleDbCommand("update sql",con);
OleDbDataAdapter mAdapter=new OleDbDataAdapter();
mAdapter.DeleteCommand=mDeleteCommand;
mAdapter.InsertCommand=mInsertCommand;
mAdapter.UpdateCommand=mUpdateCommand;
mAdapter.Update(ds,"frånKund");
}
catch(Exception fel)
{
MessageBox.Show(fel.Message,"Databasfel");
}
}
</code>
Som du ser öppnar och stänger jag inte connectionen, det ska inte behövas p g a hur DataAdaptern fungerar. Om Connection-objektet är stängt ska adaptern öppna connectionen och sedan stänga den efter sig. Om connection-objektet är öppet så lämnar adaptern det öppet efter sig. Skulle inte det fungera så lägg till con.Open() och con.Close() på lämpliga ställen.
Du har även deklarerat ditt Connection-objekt på formulärnivå ser jag så jag tar bort det ur min funktion.
Se upp för eventuella fel med Case-sensitive då jag skrivit koden direkt från skallen (vilket kanske märks :-). Glöm inte heller bort att klippa in dina SQL-satser där du skapar Command-objekten.
Håller tummarna...Sv: Uppdate Insert Delete???
Jag tar med hela den aktuella koden, och förklara sdan:
<code>
string kolumn = listBoxTotal.SelectedItem.ToString();
label14.Text="Nu uppdateras: " +kolumn ;
int check1;
int check2;
int check3;
if(checkBox1.Checked==true)
{
check1=1;
}
else
{
check1=0;
}
if(checkBox2.Checked==true)
{
check2=1;
}
else
{
check2=0;
}
if(checkBox3.Checked==true)
{
check3=1;
}
else
{
check3=0;
}
try
{
//OleDbCommand mDeleteCommand=new OleDbCommand("delete sql",con);
//OleDbCommand mInsertCommand=new OleDbCommand("insert sql",con);
OleDbCommand mUpdateCommand=new OleDbCommand("Update t_Kunder " +
" Set Kundkategori= " +
"(SELECT KundKat_Id FROM t_KundKategori " +
"WHERE KundKategori = '" + kolumn + "')," +
"Firma = '" + textBoxFirma + "'," +
"Namn = '" + textBoxNamn + "'," +
"Box = '" + textBoxBox + "'," +
"Adress = '" + textBoxAdress + "'," +
"PostOrt = '" + textBoxPostOrt + "'," +
"Tel = '" + textBoxTelefon + "'," +
"Mobil = '" + textBoxMobil + "'," +
"Fax = '" + textBoxFax + "'," +
"URL = '" + textBoxURL + "'," +
"Epost = '" + textBoxEpost + "'," +
"EjLjud = " + check1 + "," +
"Info = " + check2 + "," +
"SkickCD = " + check3 + "," +
"Anteck = '" + textBoxAnteckning + "' "+
"Where Firma = " + listBoxTotal,con);
con.Open();
OleDbDataAdapter mAdapter=new OleDbDataAdapter();
//mAdapter.DeleteCommand = mDeleteCommand;
//mAdapter.InsertCommand = mInsertCommand;
mAdapter.UpdateCommand = mUpdateCommand;
mAdapter.Update(ds,"frånKund");
con.Close();
}
catch(Exception fel)
{
MessageBox.Show(fel.Message,"Databasfel");
}
</code>
När jag tar enbart SQL:en i QA så är det inga som helst problem.
När jag försöker här så får jag felmess:
Line 1:Incorect syntax near ','.
Har du någon idé???Sv: Uppdate Insert Delete???
Det innebär att om du skriver :
<code>
string s1=textBoxFirma; // Ger kompilerings fel
string s2="hej" + textBoxFirma; // Fungerar,implicit typkonvertering till string via ToString()
</code>
så kommer första raden att generera kompileringsfel men andra raden fungerar fint, dock inte som du tänkt dig kanske.
Objektet textBoxFirma kommer alltså att typkonverteras till en sträng eftersom du skriver det mitt i en strängkonkatenering, dvs metoden textBoxFirma.ToString() kommer att anropas och den returnerar något i stil med :
"System.Windows.Forms.TextBox; Text : value"
och det är ju inte en strängen du vill ha. Du vill ha värdet av Text-propertyn. Du är alltså viktigt att du skriver "textBoxFirma.Text" för att få värdet på Text-propertyn. Så, lägg till ".Text" till alla textboxar i SQL-strängen. Detsamma gäller listboxen.
Jag är inte säker på att det löser problemet, men det borde inte fungera som det ser ut nu iallafall.
Om inte detta hjälper, sätt en breakpoint efter att SQL-strängen är skapad och plocka ut SQL-strängen och lägg in den i denna tråden. Alternativt skicka hela koden till per@hultqvist.nu så ska jag titta på det.Sv: Uppdate Insert Delete???
Samma sträng i QA allt fungerar. Men han säger ju att i line1 finns ett fel nära ','.
Det är ju dessa rader:
<code>
Update t_Kunder " +
" Set Kundkategori= " +
"(SELECT KundKat_Id FROM t_KundKategori " +
"WHERE KundKategori = '" + comboBoxKategori.Text + "'),"
</code>
Det måste ju vara så???Sv: Uppdate Insert Delete???
Skriv om det på följande vis och klipp in vad som visas i MessageBoxen...:
<code>
string sql="Update t_Kunder " +
" Set Kundkategori= " +
"(SELECT KundKat_Id FROM t_KundKategori " +
"WHERE KundKategori = '" + kolumn + "')," +
"Firma = '" + textBoxFirma.Text + "'," +
"Namn = '" + textBoxNamn.Text + "'," +
"Box = '" + textBoxBox.Text + "'," +
"Adress = '" + textBoxAdress.Text + "'," +
"PostOrt = '" + textBoxPostOrt.Text + "'," +
"Tel = '" + textBoxTelefon.Text + "'," +
"Mobil = '" + textBoxMobil.Text + "'," +
"Fax = '" + textBoxFax.Text + "'," +
"URL = '" + textBoxURL.Text + "'," +
"Epost = '" + textBoxEpost.Text + "'," +
"EjLjud = " + check1 + "," +
"Info = " + check2 + "," +
"SkickCD = " + check3 + "," +
"Anteck = '" + textBoxAnteckning.Text + "' "+
"Where Firma = " + listBoxTotal.Text;
MessageBox.Show(sql);
OleDbCommand mUpdateCommand=new OleDbCommand(sql,con);
</code>
Enklast är att sätta en breakpoint på raden där messageboxen visas och när den stannat där gå till Command Window och skriva "? sql", utan fnuttarna. Klipp sedan ut vad som returneras.Sv: Uppdate Insert Delete???
MEN JAG HAR HITTAT FELET
Det fanns ju inga fnuttar runt
"Where Firma = '" + listBoxTotal.Text + "'";
Tiosusen tack och fortsatt Glad Påsk.
Tack för att du tog upp din dybara tid. Jag önskar bara att jag kan återgällar dig.
VARNING
Jag är inte klar än...
MVH
BenniSv: Uppdate Insert Delete???
Lycka till med resten...