[T-SQL] Variabele tabel naam meegeven aan stored procedure.

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • 430xlkod
  • Registratie: Januari 2007
  • Laatst online: 05-07 23:11
Hi guys,

Ik kom er niet meer aan uit maar in elk geval heb er nu ondertussen 3 uur zoek en trail&error werk op zitten en wordt het wat moe. Ik probeer de data op te halen van mijn database via een variabele tabel naam die ik meegeef aan een stored procedure.

Stored Procedure:
SQL:
1
2
3
4
5
6
7
ALTER PROCEDURE [dbo].[showTable]
  (
  @v_tableName VARCHAR(32)
  )
AS
    EXEC('SELECT * FROM' + @v_tableName)
RETURN


C# code:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
DataSet data = new DataSet(); 
if (this.makeConnection() == true)
                {
                    //get all data
                    thisCommand.CommandText = "showTable";
                    thisCommand.CommandType = CommandType.StoredProcedure;
                    thisCommand.Parameters.AddWithValue("@v_tableName", tableName);
                    SqlDataAdapter dataAdapter = new SqlDataAdapter(thisCommand.CommandText, thisConnection);
                    dataAdapter.Fill(data);
                    closeConnection();
                    return data;
                }


En ik blijf de error krijgen:
++Procedure or function 'showTable' expects parameter '@v_tableName', which was not supplied.++

Weet iemand wat ik fout doe? Heb al talloze dingen geprobeerd ie ik gevonden had via Google en telkens leek de oplossing dynamische SQL te gebruiken maar zoals je ziet helpt het bij mij niet echt...

Bedankt alvast. Ik ga verder proberen ondertussen.

EDIT:

Oké, sorry voor het vervelen maar de fout zit blijkbaar niet op de plaats waar hij het aangeeft. De variabele wordt wel correct doorgegeven en de gegevens worden correct opgehaald enkel gaat het fout op volgende lijn:
dataAdapter.Fill(data);

Kan voor mijn part dicht.

EDIT2:
Toch niet :( .
Want als ik er het volgende van maak dan werkt het wel zoals het hoor...
C#:
1
2
3
4
5
thisCommand.CommandText = "SELECT * FROM [" + tableName +"]";
SqlDataAdapter dataAdapter = new SqlDataAdapter(thisCommand.CommandText, thisConnection);
dataAdapter.Fill(data);
closeConnection();
return data;


Ik snap er niets van.

[ Voor 18% gewijzigd door 430xlkod op 23-01-2012 17:51 ]


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Moet het @-teken niet weg in AddWithValue (weet nooit if 'ie er nou wel/niet in moet, en volgens mij is het nog driver-afhankelijk ook).

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • glrfndl
  • Registratie: Juni 1999
  • Niet online
Volgens mij moet je je parameter ook al in je commandtext meegeven en mis je ook niet een spatie na de FROM in je sproc?

Prepare for unforeseen consequences


Acties:
  • 0 Henk 'm!

  • 430xlkod
  • Registratie: Januari 2007
  • Laatst online: 05-07 23:11
In een andere methode gebruik ik ook 2 parameters en alle twee met een @-teken en dit werkt zoals het hoort.
Maar ik heb het toch even getest met verschillende combo's:

C#:
1
2
3
4
5
6
7
8
9
//get all data
thisCommand.CommandText = "showTable";
thisCommand.CommandType = CommandType.StoredProcedure;
thisCommand.Parameters.AddWithValue("@v_tableName", tableName);

//thisCommand.CommandText = "SELECT * FROM [" + tableName +"]";
SqlDataAdapter dataAdapter = new SqlDataAdapter(thisCommand.CommandText, thisConnection);
dataAdapter.Fill(data, tableName);
closeConnection();


C#:
1
2
3
4
selectedTable = cboxTables.SelectedItem.ToString();
dataset = db.getDataFromTable(selectedTable);
datatable = dataset.Tables[selectedTable];
datagridAdmin.ItemsSource = datatable.DefaultView; //[ERROR: Object reference not set to an instance of an object.]




Vervolgens zonder @-teken:
C#:
1
2
3
4
5
6
7
8
9
//get all data
thisCommand.CommandText = "showTable";
thisCommand.CommandType = CommandType.StoredProcedure;
thisCommand.Parameters.AddWithValue("v_tableName", tableName);

//thisCommand.CommandText = "SELECT * FROM [" + tableName +"]";
SqlDataAdapter dataAdapter = new SqlDataAdapter(thisCommand.CommandText, thisConnection);
dataAdapter.Fill(data, tableName);
closeConnection();


C#:
1
2
3
4
selectedTable = cboxTables.SelectedItem.ToString();
dataset = db.getDataFromTable(selectedTable);
datatable = dataset.Tables[selectedTable];
datagridAdmin.ItemsSource = datatable.DefaultView;//[ERROR: Object reference not set to an instance of an object.]




Naderhand dan dit geprobeerd:
C#:
1
2
3
4
5
6
7
8
9
//get all data
//thisCommand.CommandText = "showTable";
//thisCommand.CommandType = CommandType.StoredProcedure;
//thisCommand.Parameters.AddWithValue("v_tableName", tableName);

thisCommand.CommandText = "SELECT * FROM [" + tableName +"]";
SqlDataAdapter dataAdapter = new SqlDataAdapter(thisCommand.CommandText, thisConnection);
dataAdapter.Fill(data, tableName);
closeConnection();


C#:
1
2
3
4
selectedTable = cboxTables.SelectedItem.ToString();
dataset = db.getDataFromTable(selectedTable);
datatable = dataset.Tables[selectedTable];
datagridAdmin.ItemsSource = datatable.DefaultView;


En dit werkte perfect... Ik snap er dus echt niets van. Die stored procedure gebruiken is geen vereiste maar ik houd wel graag alles hetzelfde.

EDIT:
glrfndl, dit had ik ook al gezien en al veranderd maar gaf geen verandering zoals je hierboven ziet :) .
EDIT2:
Foutje van me, het is inderdaad daar wel door verholpen :). Hij herkende de variabele niet omdat hij zat vastgeplakt aan de FROM. Maar heb nu dus bovenstaand probleem.

[ Voor 5% gewijzigd door 430xlkod op 23-01-2012 20:17 ]


Acties:
  • 0 Henk 'm!

  • sig69
  • Registratie: Mei 2002
  • Laatst online: 22:50
Je moet ook niet de CommandText van je SqlCommand in de constructor van je SqlDataAdapter gooien, maar de SqlCommand zelf..

Roomba E5 te koop


Acties:
  • 0 Henk 'm!

  • 430xlkod
  • Registratie: Januari 2007
  • Laatst online: 05-07 23:11
Dan werkt het juist niet en krijg ik een error?

Acties:
  • 0 Henk 'm!

  • sig69
  • Registratie: Mei 2002
  • Laatst online: 22:50
Ik zie dat in geen van je code samples, je hebt overal dit staan:
code:
1
SqlDataAdapter dataAdapter = new SqlDataAdapter(thisCommand.CommandText, thisConnection);

Ipv:
code:
1
SqlDataAdapter dataAdapter = new SqlDataAdapter(thisCommand, thisConnection);

(volgens mij, het is wat roestig...)

Roomba E5 te koop


Acties:
  • 0 Henk 'm!

  • 430xlkod
  • Registratie: Januari 2007
  • Laatst online: 05-07 23:11
Als ik gewoon 'thisCommand' doe zonder de '.CommandText' krijg ik een error. Dat bedoel ik.

Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Ik zit op m'n iPhone dus linkjes sprikkelen is wat omslachtig, maar heb je er al eens gewoon MSDN bijgepakt?

[edit]
Je gebruikt nu deze constructor (die een string verwacht als eerste parameter); je wil juist deze constructor gebruiken.
De connection geef je dan niet door middels de tweede parameter; die zit namelijk al in de SqlCommand; in diens constructor kun je wél de SqlConnection meegeven.

Zoals je daar ook in de examples kunt zien moet het @ teken wél bij het toevoegen van examples worden opgegeven; dat was dus my bad (maar zoals ik zei: in sommige gevallen moet 't volgens mij juist niet, maar dat is dan weer (RDBMS)driver-afhankelijk ofzo).
Het helpt als je volgende keer ook even aangeeft wélke error; en sterker: het zou helpen als je de error gewoon eens leest want er staat geheid wat er mis is.

Anyway; het gedrag is dan ook prima te verklaren: je geeft niet het SqlCommand object door maar enkel de query die 't SqlCommand bevat en dus niet ook diens (door jou toegevoegde) parameters. Nogal wiedes dat 't dan niet werkt.

[ Voor 114% gewijzigd door RobIII op 23-01-2012 21:24 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • 430xlkod
  • Registratie: Januari 2007
  • Laatst online: 05-07 23:11
Ik snap het punt niet dat je wil uitleggen. Het werkt toch tot op de hoogte van wanneer ik de opgehaalde DataSet wil doorgeven aan een DataGrid.
Ik doe bij mij SqlDataAdapter toch volgende constructor aanroepen:
C#:
1
public SqlDataAdapter(string selectCommandText, SqlConnection selectConnection)


Daar verwacht hij een string met het commando in en de connection. Die geef ik toch netjes mee?

Want dit werkt namelijk:
C#:
1
2
3
4
5
6
7
8
//Method --> getDataFromTable(String tableName)
makeConnection();
thisCommand.CommandText = "showTable";
thisCommand.CommandType = CommandType.StoredProcedure;
thisCommand.Parameters.AddWithValue("@v_tableName", tableName);
SqlDataAdapter dataAdapter = new SqlDataAdapter(thisCommand.CommandText, thisConnection);
dataAdapter.Fill(data, tableName);
closeConnection();


Maar dan komt er hier een error op de laatste lijn met de error: "Object reference not set to an instance of an object.".
C#:
1
2
3
4
selectedTable = cboxTables.SelectedItem.ToString();
dataset = db.getDataFromTable(selectedTable);
datatable = dataset.Tables[selectedTable];
datagridAdmin.ItemsSource = datatable.DefaultView; //**********





EDIT:
Toch evengoed jou suggestie geprobeerd om te zien wat je juist bedoelde en het werkt :) .
Jou suggestie:
C#:
1
2
3
4
5
SqlCommand test = new SqlCommand("showTable", thisConnection);
test.CommandType = CommandType.StoredProcedure;
test.Parameters.AddWithValue("@v_tableName", tableName);
SqlDataAdapter dataAdapter = new SqlDataAdapter(test);
dataAdapter.Fill(data, tableName);


Dit werkt perfect. Bedankt nogmaals. Is het dan verstandig om in de toekomst altijd de connection object mee te geven aan het sqlcommand object in plaats van zoals ik het had?

EDIT2:
Ik snap de fout al die ik had gemaakt. Ik gaf het sqlcommando text type door (string) in plaats van het sqlcommando object zelf.



Kom ik wel direct bij mijn volgende probleem waar ik absoluut niet aan uit kom.
Ik heb dus de DataSet gebonden aan de DataGrid door uit de DataSet de gekozen tabelnaam te kiezen. De DataGrid die ik heb staan op het WPF is dynamisch in die zin dat ik elke tabel kan inlezen. Maar hoe kan ik nu veranderingen die ik heb aangebracht in het DataGrid terug opslaan naar de database?
Ik heb geprobeerd om de gewijzigde waardes terug op te slaan in een nieuwe DataSet en deze dan mee te geven aan een methode die in de database class staat. Maar hoe moet ik dan verder?

Kleine weergave:
Afbeeldingslocatie: http://dl.dropbox.com/u/16312033/Capture.PNG



Schiet me niet af als het niet helemaal een elegante oplossing is maar heb volgende gefabriceerd.
frmAdmin:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private void btnShowChosenTable_Click(object sender, RoutedEventArgs e)
        {            
            //fill the datagrid with data from chosen table in combobox!            
            selectedTable = cboxTables.SelectedItem.ToString();
            dataset = db.getDataFromTable(selectedTable);
            datatable = dataset.Tables[selectedTable];
            datagridAdmin.ItemsSource = datatable.DefaultView;            
        }

        private void btnSaveChanges_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                db.updateTable(selectedTable, datatable);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }


DatabaseClass.cs:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public bool updateTable(String tableName, DataTable datatable)
        {
            try
            {
                if (this.makeConnection() == true)
                {
                    using (SqlBulkCopy bulkcopy = new SqlBulkCopy(thisConnection.ConnectionString))
                    {
                        //Set destination table name
                        //to table previously created.
                        bulkcopy.DestinationTableName = tableName;

                        try
                        {
                            bulkcopy.WriteToServer(datatable);
                        }
                        catch (Exception ex)
                        {
                            logger.LogToFile(ex.Message);
                        }
                    }
                }
                closeConnection();
                return true;
            }
            catch (Exception ex)
            {
                closeConnection();
                logger.LogToFile(ex.Message);
                MessageBox.Show(ex.ToString());
                return false;
            }            
        }


Maar het probleem is dat de data er nu dubbel in komt te staan in de bestaande tabel. Is er dan een andere mogelijk dan om nog in de methode in de DatabaseClass.cs een DELETE commando uit te voeren?

[ Voor 66% gewijzigd door 430xlkod op 24-01-2012 12:51 ]

Pagina: 1