[C#] Updaten van joined tables

Pagina: 1
Acties:

  • ZeroCode
  • Registratie: Februari 2002
  • Laatst online: 04-03 19:41
Ik ben nu een tijd bezig met het zoeken naar een antwoord om joined tables te kunnen updaten. Ik zal het eerst uitleggen met behulp van wat screenshots.

De applicatie in runtime:
Afbeeldingslocatie: http://xs4all.nl/~dario/got/versienummers.JPG

De datagrid is een product van 2 tabellen:
Afbeeldingslocatie: http://xs4all.nl/~dario/got/table1.JPG

en

Afbeeldingslocatie: http://xs4all.nl/~dario/got/table2.JPG

Ik gebruik de volgende code om de tables te joinen:
code:
1
2
3
4
5
6
7
8
9
10
11
12
private void FillVersies()
{
    strCommand = "SELECT s.Applicatie as Applicatie, ID, Versienr as Versienummer, 
    Datum_update as [Datum Update] FROM Kg_DbSoftwareVersie as v join Kg_DBSoftware as s on 
    s.appID = v.applicatie where refKcode = '" + cbKlant.Text + "'";
   
    dataAdapter = new SqlDataAdapter(strCommand, strConnection);
    dataAdapter.Fill(dataSet, "Versies");
    dgVersies.DataSource=dataSet;
    dgVersies.DataMember="Versies";
    SqlCommandBuilder cmdBldr = new SqlCommandBuilder(dataAdapter);
}


Nu wil ik dus eigenlijk de kolom versienummer kunnen updaten, maar bij het aanroepen van:
code:
1
 dataAdapter.Update(dataSet, "Versies");


Geeft hij de volgende error:
Dynamic SQL generation is not supported against multiple base tables.

Opzich logisch maar wie weet hoe ik dit op een andere manier kan doen? Ik heb wel een werkende manier gevonden door middel van relation aanleggen, maar dit is tevens niet de bedoeling. Ik wil het visueel houden zoals hier:
Afbeeldingslocatie: http://xs4all.nl/~dario/got/versienummers.JPG

Het enige wat ik wil is het versienummer kunnen veranderen.

  • whoami
  • Registratie: December 2000
  • Laatst online: 11:43
Tja, da's nogal logisch.
Als je gebruik maakt van DataSets / DataAdapters, dan kunnen er, als je geen InsertCommand / UpdateCommand, etc... aan die data-adapter meegeeft, automatisch SQL statements gegenereerd worden voor iedere datatable in de dataset. Deze zorgen er dus dan voor dat er updates kunnen doorgevoerd worden als je de update method van de data-adapter aanroept.
Echter, jij zit hier met een DataTable die gegevens haalt uit meer dan één tabel. Voor die tabel kunnen er dus niet automatisch InsertCommands/UpdateCommands gegenereerd worden.

Wat je nu zou kunnen doen, is zelf een UpdateCommand gaan maken, en die toevoegen aan je DataAdapter. Dan zou je het normaal gezien moeten kunnen oplossen.

PS: kijk ook eens naar parametrized queries.

[ Voor 5% gewijzigd door whoami op 11-08-2005 20:30 ]

https://fgheysels.github.io/


  • ZeroCode
  • Registratie: Februari 2002
  • Laatst online: 04-03 19:41
whoami schreef op donderdag 11 augustus 2005 @ 20:30:
Tja, da's nogal logisch.
Als je gebruik maakt van DataSets / DataAdapters, dan kunnen er, als je geen InsertCommand / UpdateCommand, etc... aan die data-adapter meegeeft, automatisch SQL statements gegenereerd worden voor iedere datatable in de dataset. Deze zorgen er dus dan voor dat er updates kunnen doorgevoerd worden als je de update method van de data-adapter aanroept.
Echter, jij zit hier met een DataTable die gegevens haalt uit meer dan één tabel. Voor die tabel kunnen er dus niet automatisch InsertCommands/UpdateCommands gegenereerd worden.

Wat je nu zou kunnen doen, is zelf een UpdateCommand gaan maken, en die toevoegen aan je DataAdapter. Dan zou je het normaal gezien moeten kunnen oplossen.

PS: kijk ook eens naar parametrized queries.
Die laatste link is zeer handig, ik kan alleen 1 nadeel vinden in deze oplossing. Ik kan de waardes uit de datagrid niet vinden die zijn veranderd. Alleen de row die is veranderd, namelijk met:
code:
1
(dataSet.HasChanges(DataRowState.Modified)


Ik kan alleen niet de waardes krijgen die veranderd zijn. Bij een textbox is het makelijker, uit een datagrid krijg ik ze niet.

  • whoami
  • Registratie: December 2000
  • Laatst online: 11:43
Hoe bedoel je ?
Je kan toch in de DataTable de originele waardes uit de gewijzigde data-row opvragen, en trouwens, waarom zou je dat nodig hebben ?

https://fgheysels.github.io/


  • ZeroCode
  • Registratie: Februari 2002
  • Laatst online: 04-03 19:41
whoami schreef op donderdag 11 augustus 2005 @ 21:12:
Hoe bedoel je ?
Je kan toch in de DataTable de originele waardes uit de gewijzigde data-row opvragen, en trouwens, waarom zou je dat nodig hebben ?
Hoe bedoel je ?
Je kan toch in de DataTable de originele waardes uit de gewijzigde data-row opvragen, en trouwens, waarom zou je dat nodig hebben ?[/quote]

Als ik dit wil gebruiken:
code:
1
2
3
4
5
6
7
8
9
10
string sSQL = "INSERT INTO personen (naam, voornaam) " +
              "VALUES (@p_naam, @p_voornaam)";
              
SqlCommand1.CommandText = sSQL;

SqlCommand1.Parameters.Add ("@p_naam", SqlDbType.Varchar);
SqlCommand1.Parameters.Add ("@p_voornaam", SqlDbType.Varchar);

SqlCommand1.Parameters["@p_naam"].Value = txtNaam.Text;
SqlCommand1.Parameters["@p_voornaam"].Value = txtVoornaam.Text;


Ik moet die waardes uit de datagrid lezen toch die veranderd zijn, hierboven doe je dat simpel door de waardes uit txtVoornaam en txtNaam te lezen. Hetzelfde moet ik doen bij de datagrid.

  • whoami
  • Registratie: December 2000
  • Laatst online: 11:43
Als je een INSERT doet, dan ga je een nieuwe rij toevoegen. Dan heb je toch geen 'originele' en 'veranderde' gegevens ?

Als je een update doet, dan kan je toch gewoon de 'huidige' gegevens gebruiken om je update te doen ? De gegevens die veranderd zijn, zullen overschreven worden; de gegevens die niet veranderd zijn, worden met dezelfde waarde overschreven ?

Als je dit probleem hebt, om de juiste 'columns' aan de juiste parameters te mappen, dan kan je aan je parameter een source-column meegeven dacht ik.

https://fgheysels.github.io/


  • ZeroCode
  • Registratie: Februari 2002
  • Laatst online: 04-03 19:41
whoami schreef op vrijdag 12 augustus 2005 @ 11:40:
Als je een INSERT doet, dan ga je een nieuwe rij toevoegen. Dan heb je toch geen 'originele' en 'veranderde' gegevens ?

Als je een update doet, dan kan je toch gewoon de 'huidige' gegevens gebruiken om je update te doen ? De gegevens die veranderd zijn, zullen overschreven worden; de gegevens die niet veranderd zijn, worden met dezelfde waarde overschreven ?

Als je dit probleem hebt, om de juiste 'columns' aan de juiste parameters te mappen, dan kan je aan je parameter een source-column meegeven dacht ik.
Het gaat inderdaad over het updaten. Ik ga zoeken of ik of ik juiste columns kan mappen. Bedankt iig voor de info, laat het nog wel even weten als het gelukt is.

  • ZeroCode
  • Registratie: Februari 2002
  • Laatst online: 04-03 19:41
Het updaten gaat nog steeds fout, ik heb de volgende code gebruikt:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
            string query = "Update Kg_dbSoftwareVersie Set Versienr = @VersieNummer, Applicatie = @Applicatie, refKcode = @refKcode WHERE Id = @Id";
            
            SqlConnection con = new SqlConnection(strConnection);
            con.Open();
            dataAdapter.UpdateCommand = new SqlCommand(query, con); 

            SqlParameter workParam = null; 

            workParam = dataAdapter.UpdateCommand.Parameters.Add("@id", SqlDbType.NChar); 
            workParam.SourceColumn = "Id"; 
            workParam.SourceVersion = DataRowVersion.Original; 
        
            workParam = dataAdapter.UpdateCommand.Parameters.Add("@VersieNummer", SqlDbType.NChar, 50); 
            workParam.SourceVersion = DataRowVersion.Current; 
            workParam.SourceColumn = "versienr"; 

            workParam = dataAdapter.UpdateCommand.Parameters.Add("@Applicatie", SqlDbType.Int); 
            workParam.SourceVersion = DataRowVersion.Current;
            workParam.SourceColumn = "Applicatie"; 
            dataAdapter.Update(dataSet, "versies");
            con.Close();


Foutmelding:
De indeling van de invoerreeks is onjuist.

Waar hij denk ik problemen mee heeft is dat hij het naar de datatable "versies" wil schrijven. Iemand een idee om het anders weg te schrijven?

  • whoami
  • Registratie: December 2000
  • Laatst online: 11:43
Hoe ziet jouw select-command eruit die de datatable heeft opgevuld ?

https://fgheysels.github.io/


  • ZeroCode
  • Registratie: Februari 2002
  • Laatst online: 04-03 19:41
whoami schreef op vrijdag 12 augustus 2005 @ 14:24:
Hoe ziet jouw select-command eruit die de datatable heeft opgevuld ?
code:
1
2
3
strCommand = "SELECT s.Applicatie as Applicatie, ID, Versienr as Versienummer, 
Datum_update as [Datum Update] FROM Kg_DbSoftwareVersie as v join Kg_DBSoftware as s on 
s.appID = v.applicatie where refKcode = '" + cbKlant.Text + "'";


Dit is dus die join, maar ik kan toch niet alles gaan updaten toch?

Ik probeer het nu met 3 datatables waarvan ik maar 1 datatable update en niet de gejoinde table. Lijkt me niet netjes maar ik probeer het iig.

[ Voor 16% gewijzigd door ZeroCode op 12-08-2005 14:49 ]


  • whoami
  • Registratie: December 2000
  • Laatst online: 11:43
Die ene source-column (in je parameter-definitie), zal je Versienummer moeten noemen ipv versienr denk ik.

[ Voor 5% gewijzigd door whoami op 12-08-2005 14:48 ]

https://fgheysels.github.io/


  • ZeroCode
  • Registratie: Februari 2002
  • Laatst online: 04-03 19:41
whoami schreef op vrijdag 12 augustus 2005 @ 14:48:
Die ene source-column (in je parameter-definitie), zal je Versienummer moeten noemen ipv versienr denk ik.
Probleem is denk ik ook dat ik dezelfde dataSet wil updaten, kan het natuurlijk ook met een ExecuteNonQuery proberen :)

  • whoami
  • Registratie: December 2000
  • Laatst online: 11:43
ZeroCode schreef op vrijdag 12 augustus 2005 @ 14:51:
[...]


Probleem is denk ik ook dat ik dezelfde dataSet wil updaten, kan het natuurlijk ook met een ExecuteNonQuery proberen :)
:?
Je doet geen update van een 'dataset', maar van de data in de databank.

https://fgheysels.github.io/


  • ZeroCode
  • Registratie: Februari 2002
  • Laatst online: 04-03 19:41
whoami schreef op vrijdag 12 augustus 2005 @ 14:51:
[...]


:?
Je doet geen update van een 'dataset', maar van de data in de databank.
Nee ik bedoelde, voorgaand zie je:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
            workParam = dataAdapter.UpdateCommand.Parameters.Add("@id", SqlDbType.NChar); 
            workParam.SourceColumn = "Id"; 
            workParam.SourceVersion = DataRowVersion.Original; 
        
            workParam = dataAdapter.UpdateCommand.Parameters.Add("@VersieNummer", SqlDbType.NChar, 50); 
            workParam.SourceVersion = DataRowVersion.Current; 
            workParam.SourceColumn = "versienr"; 

            workParam = dataAdapter.UpdateCommand.Parameters.Add("@Applicatie", SqlDbType.Int); 
            workParam.SourceVersion = DataRowVersion.Current;
            workParam.SourceColumn = "Applicatie"; 
            dataAdapter.Update(dataSet, "versies");
            con.Close();


dataAdapter.Update(dataSet, "versies");

daar gaat het denk ik fout. Die datatable is namelijk gejoined.

Ik zie trouwens meerdere fouten, datatypes komen niet overeen, ik mis de refKcode als parameter etc etc. Ik kan iig weer even vooruit thanx!

[ Voor 13% gewijzigd door ZeroCode op 12-08-2005 14:57 ]


  • whoami
  • Registratie: December 2000
  • Laatst online: 11:43
Die datatable is namelijk gejoined.
Die is in je DataSet niet gejoined.

https://fgheysels.github.io/


  • ZeroCode
  • Registratie: Februari 2002
  • Laatst online: 04-03 19:41
whoami schreef op vrijdag 12 augustus 2005 @ 15:00:
[...]

Die is in je DataSet niet gejoined.
Ja maar ik wil de verandering in Versienummer wel wegschrijven in een tabel in een database.

  • whoami
  • Registratie: December 2000
  • Laatst online: 11:43
ZeroCode schreef op vrijdag 12 augustus 2005 @ 15:01:
[...]


Ja maar ik wil de verandering in Versienummer wel wegschrijven in een tabel in een database.
Ja, en dat doe je idd door die update method van je data-adapter uit te voeren.

Ik heb net ff een testje gemaakt:
Ik maak een DataAdapter aan, die een select command en een update command heeft; m'n SELECT command joined 2 tabellen, zoals jij het doet.
M'n UpdateCommand doet een update in één tabel:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
SqlCommand cmdSelect = new SqlCommand();
cmdSelect.Connection = conn;
cmdSelect.CommandText = "SELECT tblApplication.applicationname, tbldata.versienr, tblapplication.id \n" +
                        "FROM tblApplication \n" +
                        "INNER JOIN tblData on tblData.applicationid = tblapplication.id WHERE tbldata.[current] = 1";
                        
SqlCommand cmdUpdate = new SqlCommand();
cmdUpdate.Connection = conn;
cmdUpdate.CommandText = "UPDATE tblData SET tblData.versienr = @vnr WHERE applicationid = @appid AND [current] = 1";
cmdUpdate.Parameters.Add ("@vnr", SqlDbType.NChar, 10, "versienr");
cmdUpdate.Parameters.Add ("@appid", SqlDbType.Int, 0, "id");   
            
da.SelectCommand = cmdSelect;
da.UpdateCommand = cmdUpdate;
            
da.Fill (ds);
            
dataGrid1.DataSource = ds.Tables[0];


Als ik dan iets in m'n datagrid wijzig, en ik klik op m'n update-knop (die gewoon de da.Update(ds) uitvoert), dan zijn mijn gegevens gewijzigd.

https://fgheysels.github.io/


  • ZeroCode
  • Registratie: Februari 2002
  • Laatst online: 04-03 19:41
whoami schreef op vrijdag 12 augustus 2005 @ 15:11:
[...]


Ja, en dat doe je idd door die update method van je data-adapter uit te voeren.

Ik heb net ff een testje gemaakt:
Ik maak een DataAdapter aan, die een select command en een update command heeft; m'n SELECT command joined 2 tabellen, zoals jij het doet.
M'n UpdateCommand doet een update in één tabel:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
SqlCommand cmdSelect = new SqlCommand();
cmdSelect.Connection = conn;
cmdSelect.CommandText = "SELECT tblApplication.applicationname, tbldata.versienr, tblapplication.id \n" +
                        "FROM tblApplication \n" +
                        "INNER JOIN tblData on tblData.applicationid = tblapplication.id WHERE tbldata.[current] = 1";
                        
SqlCommand cmdUpdate = new SqlCommand();
cmdUpdate.Connection = conn;
cmdUpdate.CommandText = "UPDATE tblData SET tblData.versienr = @vnr WHERE applicationid = @appid AND [current] = 1";
cmdUpdate.Parameters.Add ("@vnr", SqlDbType.NChar, 10, "versienr");
cmdUpdate.Parameters.Add ("@appid", SqlDbType.Int, 0, "id");   
            
da.SelectCommand = cmdSelect;
da.UpdateCommand = cmdUpdate;
            
da.Fill (ds);
            
dataGrid1.DataSource = ds.Tables[0];


Als ik dan iets in m'n datagrid wijzig, en ik klik op m'n update-knop (die gewoon de da.Update(ds) uitvoert), dan zijn mijn gegevens gewijzigd.
Ik ga dit uitvoerig testen en in mijn applicatie proberen te verwerken. Ik laat het je nog even weten...

  • ZeroCode
  • Registratie: Februari 2002
  • Laatst online: 04-03 19:41
Ik krijg na bij de volgende regel een NullRefrence exception:
da.SelectCommand = cmdSelect;

Enig idee waarom?

[ Voor 54% gewijzigd door whoami op 16-08-2005 17:24 ]


  • whoami
  • Registratie: December 2000
  • Laatst online: 11:43
Omdat een of ander object null is. Je data-adapter in dit geval waarschijnlijk, maar dat kan je zelf wel makkelijk onderzoeken door je code eens te debuggen. VS.NET heeft genoeg faciliteiten om te debuggen.

Ik heb je link maar weggehaald, want P&W is nu ook geen debug-clubje.

[ Voor 15% gewijzigd door whoami op 16-08-2005 17:24 ]

https://fgheysels.github.io/


  • ZeroCode
  • Registratie: Februari 2002
  • Laatst online: 04-03 19:41
whoami schreef op dinsdag 16 augustus 2005 @ 17:23:
Omdat een of ander object null is. Je data-adapter in dit geval waarschijnlijk, maar dat kan je zelf wel makkelijk onderzoeken door je code eens te debuggen. VS.NET heeft genoeg faciliteiten om te debuggen.

Ik heb je link maar weggehaald, want P&W is nu ook geen debug-clubje.
Klopt is ook zo, ik was er net achter maar [current] herkent de C# compiler niet. Dit ken ik zelf ook niet van SQL server. Hij valt over "WHERE tbldata.[current] = 1" De compiler denkt dat dit een column moet zijn.
Tevens vind ik hier niks over in google. Je geeft toch gewoon een query mee?

[ Voor 5% gewijzigd door ZeroCode op 16-08-2005 17:31 ]


  • whoami
  • Registratie: December 2000
  • Laatst online: 11:43
De compiler kan dat helemaal niet weten, en valt daar ook niet over. De C# compiler weet helemaal niks af van die columns in je SQL code.
Die NULL exception krijg je, omdat je Data-Adapter niet geinitialiseerd is.

Current is een reserved word in SQL Server, en door blok-haken errond te zetten, los je het probleem op dat hij 'current' niet kent. Ik snap nu ook niet meer waar je probleem nu nog zit , of welke fout je nu nog krijgt (ervan uitgaand dat je die nullreferenceexception hebt opgelost).

https://fgheysels.github.io/


  • ZeroCode
  • Registratie: Februari 2002
  • Laatst online: 04-03 19:41
Die nullreferenceexception is opgelost, ik was idd vergeten de DataAdapter te initialiseren.
Nu heb ik de query geprobeert in Query Analyser maar krijg daar tevens dezelfde foutmelding. Namelijk:


SELECT tblApplication.applicationname, tbldata.versienr, tblapplication.id FROM tblApplication INNER JOIN tblData on tblData.applicationid = tblapplication.id WHERE tbldata.[current] = 1

Server: Msg 207, Level 16, State 3, Line 1
Invalid column name 'current'.

  • whoami
  • Registratie: December 2000
  • Laatst online: 11:43
Je hebt toch wel een veld in je tblData tabel die current heet ?

https://fgheysels.github.io/


  • ZeroCode
  • Registratie: Februari 2002
  • Laatst online: 04-03 19:41
[quote]whoami schreef op dinsdag 16 augustus 2005 @ 20:12:
Nevermind ik ben er volgens mij achter :| dumbass me

[ Voor 71% gewijzigd door ZeroCode op 16-08-2005 20:38 ]


  • whoami
  • Registratie: December 2000
  • Laatst online: 11:43
Eh, tja, als je geen veld 'current' hebt, dan kan hij dat natuurlijk ook niet vinden....

Dat 'current' veld had ik gewoon in mijn voorbeeld gebruikt. Het is natuurlijk wel de bedoeling dat je dat voorbeeld kunt gebruiken, maar dan zal je wel wat moeite moeten doen om het in jouw specifieke geval te moeten laten passen.
Ik heb niet jouw datamodel gebruikt, ik heb ff snel een databankje gemaakt om het principe te illustreren.
Die current is dus een veld dat ik zelf gebruik om te filteren.

[ Voor 7% gewijzigd door whoami op 16-08-2005 20:39 ]

https://fgheysels.github.io/


  • ZeroCode
  • Registratie: Februari 2002
  • Laatst online: 04-03 19:41
whoami schreef op dinsdag 16 augustus 2005 @ 20:35:
Eh, tja, als je geen veld 'current' hebt, dan kan hij dat natuurlijk ook niet vinden....

Dat 'current' veld had ik gewoon in mijn voorbeeld gebruikt. Het is natuurlijk wel de bedoeling dat je dat voorbeeld kunt gebruiken, maar dan zal je wel wat moeite moeten doen om het in jouw specifieke geval te moeten laten passen.
Ik heb niet jouw datamodel gebruikt, ik heb ff snel een databankje gemaakt om het principe te illustreren.
Die current is dus een veld dat ik zelf gebruik om te filteren.
OMG!
Hij werkt... Nu kan ik gaan analyseren want ik nou precies verkeerd doe bij me echte applicatie. Ik heb het nu ook kleinschalig gemaakt en jou tips gevolgt maar het werkt!

Echt heel erg bedankt, ik ga dit verder onderzoeken.

*BIG THANX*
Pagina: 1