none
Fill Data Grid by SP [VS 2010 .NET 4 VB WindowsForm ] RRS feed

  • Frage

  • Hallo zusammen,

    ich moechte ein kleines VB-Programm zu Diskussion stellen. Mein Ziel war das Ergenis eines SELECT -Statements da in eine Stored Procedure (SQL SERVER 2005)  laeuft in ein DataGridView zu bekommen. Ich habe alle moeglichen Beispiele gesehen, aber nicht eines was so kompact war. Moeglicherwiese ist es nur Zufall das es so funtioniert. Bitte seht euch das mal an.

    Public Class ServerUserLogIns
    
      Private Sub ServerUserLogIns_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        
        Dim myCommand = New SqlClient.SqlDataAdapter("EXEC GetPatGenUsers", WindowsApplication1.My.Settings.PatGenConnectionString)
        Dim ds As Data.DataSet = New Data.DataSet
    
        myCommand.Fill(ds)
    
        DataGridView1.DataSource = ds.Tables(0) ' there is just one table
    
        DataGridView1.Show()
    
      End Sub
    End Class
    

    Danke

    Rolf

    Samstag, 23. Oktober 2010 21:09

Antworten

Alle Antworten

  • Hallo Rolf,

    kein Zufall, aber auch nichts neues. Besser ggf., über den "CommandType.StoredProcedure" zu gehen, dann kann man auch das "Exec" noch weglassen.

    [Konfigurieren von Parametern und Parameterdatentypen (ADO.NET)]
    [Gewusst wie: Ausführen einer gespeicherten Prozedur, die Zeilen zurückgibt]
    [Using Stored Procedures in Conjuction with DataAdapter]

    Gründe für das eine oder andere:
    [CommandType.Text vs CommandType.StoredProcedure - Stack Overflow]

    Ggf. interessiert es Dich ja auch, dass man es auch noch viel kompakter (sogar ohne eigenen geschriebenen Code) nur mit dem Designer schaffen kann:

    • Menü Daten / Datenquellen anzeigen / Datenbank hinzufügen / DataSet / unter "Gespeicherte Prozeduren" die gewünschte abhaken / (ggf. "DataGridView" in der ComboBOx des Datenquellenfensters für die Prozedur wählen) und in dieses Form ziehen / F5.

     

     


    ciao Frank
    • Als Antwort markiert Rolf Kemper Sonntag, 24. Oktober 2010 19:28
    Sonntag, 24. Oktober 2010 17:21
  • Hallo Fank,

     

    ich habe auch mal den Weg ohne geschrieben Code versucht.

    Es wird eine DataSource generiert, aber die ist leer (kein Tablellsymbol darunter)
    Wo holt denn der wizard die information her ?

    Hier ist der SQL CODE

    ALTER PROCEDURE [dbo].[GetPatGenUsers]
    	
    AS
    BEGIN
    	CREATE TABLE #tmpUsers 
    	( 
    		spid		INT ,
    		eicd		INT ,
    		[status]	VARCHAR(50) , 
    		loginame	VARCHAR(50) ,
    		hostname	VARCHAR(50) , 
    		blk			INT ,
    		dbname		VARCHAR(50) ,
    		cmd			VARCHAR(50) ,
    		request_id	INT
    	) 
    	 
    	-- SET NOCOUNT ON added to prevent extra result sets from
    	-- interfering with SELECT statements.
    	SET NOCOUNT ON;
    
    	INSERT INTO #tmpUsers EXEC sp_who 
    
      -- Insert statements for procedure here
    	SELECT 	RTRIM(loginame) as 'loginname' , RTRIM(hostname) as 'hostname' , RTRIM([status]) as 'status' , RTRIM(cmd) as 'comd' FROM #tmpUsers WHERE dbname = 'PatGen'
    END
    
    

     

    Was sollte denn unter dem DatsetIcon (Angezeigte  Datasources) angezeigt werden ?

    Gruss

    Rolf

    Montag, 25. Oktober 2010 07:47
  • Hallo Rolf,

    Unter "kompakt" verstehst Du hoffentlich nichtdie Zahl der zu tippenden Zeichen.

    Den zu schreibenden Code übersichtlich und vor allem wartbar zu machen,
    kann man das durch eine entsprechende Organisation erreichen.
    Für obiges Beispiel "reicht" schon eine Hilfsklasse für gängige Abrufe.

    Um das Ausgangsbeispiel auseinanderzunehmen:

    Es ist durchaus ein Unterschied ob EXEC oder CommandType.StoredProcedure verwendet wird.
    Bei StoredProcedure wird ein RPC Aufruf intern verwendet,
    der effizienter ist - auch wenn hierfür nicht von Belang.
    Erkennbar an einem RPC:Starting/Completed Ereignis im SQL Profiler,
    im Gegensatz zu einem SQL:BatchStarted/Complete beim EXEC Aufruf.

    Und da hier die fehlende Überladung für den SqlDataAdapter Konstruktor "stört",
    dem kann man relativ einfach abhelfen - siehe Beispiel.
    Und auch Visual Basic hilft in aktuelleren Versionen ein wenig mit ;-)

    Im Beispiel habe ich ein (user)DataGridView und einen refresh(Button) eingebaut:

     

    Imports System.Data.SqlClient
    
    Public Class ShowUserForm
      Private Sub ShowUserForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.userDataGridView.DataSource = GetUsers()
      End Sub
    
      Private Sub refreshButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles refreshButton.Click
        Me.userDataGridView.DataSource = GetUsers()
      End Sub
    
      Private Function GetUsers() As DataTable
        ' Wrapper für die verschiedenen Varianten
        'Return GetUsersExec()
        'Return GetUsersProc()
        'Return GetDataTable("dbo.GetPatGenUsers", CommandType.StoredProcedure)
        Return GetDataTable("dbo.ShowDbUsers", CommandType.StoredProcedure)
      End Function
    
      Private Function GetUsersExec() As DataTable
        Using adapter As New SqlDataAdapter("EXEC dbo.GetPatGenUsers", My.Settings.NorthwindConnectionString)
          Dim table As New DataTable
          adapter.Fill(table)
          Return table
        End Using
      End Function
    
      Private Function GetUsersProc() As DataTable
        Using adapter As New SqlDataAdapter(New SqlCommand( _
          "dbo.GetPatGenUsers", _
          New SqlConnection(My.Settings.NorthwindConnectionString)) _
            With {.CommandType = CommandType.StoredProcedure})
    
          Dim table As New DataTable
          adapter.Fill(table)
          Return table
        End Using
      End Function
    
      ''' <summary>
      ''' Direkt Abrufe => später eigene Klasse
      ''' </summary>
      ''' <remarks>Weitere Überladungen mit Parametern usw. wären ggf. hilfreich.</remarks>
      Public Shared Function GetDataTable( _
        ByVal commandText As String, _
        Optional ByVal commandtype As CommandType = CommandType.Text) As DataTable
        Using adapter As New SqlDataAdapter(New SqlCommand( _
          commandText, _
          New SqlConnection(My.Settings.NorthwindConnectionString)) _
            With {.CommandType = commandtype})
    
          Dim table As New DataTable
          adapter.Fill(table)
          Return table
        End Using
      End Function
    
    End Class
    

     

    "GetDataTable" sollte in einer eigenen Klasse existieren.
    Dort kann man dann auch Dinge wie das verwalten der Connection etc. implementieren.

    Zu Deiner Prozedur:
    Die lässt sich mit dem DataSet Designer nicht verwenden, da dort mit SET FMTONLY ON gearbeitet wird.
    Und da dort kein SQL ausgeführt wird, gibt es auch keine temporäte Tabelle. Und somit keine Spalten-Ausgabe,
    mit der der Designer seinen Code erzeugen könnte.

    Der Aufruf von sp_who stellt hier eher einen Umweg dar.
    Ab SQL Server 2005 und später kann man das durch Abrufen von Verwaltungssichten erreichen.
    Und auch einige Informationen mehr "herauskitzeln". Eine mögliche (angelehnte) Prozedur:

     

    CREATE PROC dbo.ShowDbUsers
    AS
    	SELECT 
    		s.session_id AS spid,
    		s.login_name AS loginname,
    		s.host_name AS hostname,
    		s.status,
    		s.login_time AS logintime,
    		s.last_request_start_time AS starttime,
    		s.last_request_end_time AS endtime,
    		r.command,
    		r.sqltext
    	FROM sys.dm_exec_sessions AS s 
    	-- alternativ sys.dm_exec_connections (most_recent_sql_handle)
    	LEFT JOIN (SELECT
    			req.session_id,
    			req.start_time,
    			req.status,
    			req.command,
    			t.text AS sqltext
    		FROM sys.dm_exec_requests AS req
    		CROSS APPLY sys.dm_exec_sql_text(req.sql_handle) AS t
    		WHERE req.database_id = DB_ID()	-- akutelle Datenbank
    	) AS r ON r.session_id = s.session_id
    	WHERE s.session_id > 50			-- ohne Systemprozesse
    		-- AND s.session_id <> @@SPID	-- ohne eigene Abfrage
    	ORDER BY s.session_id
    GO
    

    Ausgefeiltere Varianten wären dort denkbar. Je nachdem was Du dort alles anzeigen möchtest.
    Ich habe beispielhaft den SQL Text eingebunden, um eine der "neueren" Möglichkeiten zu zeigen.

    Gruß Elmar

    Montag, 25. Oktober 2010 10:17
    Beantworter
  • Hallo Rolf,

        > ich habe auch mal den Weg ohne geschrieben Code versucht.

    ok.

        > Es wird eine DataSource generiert, aber die ist leer (kein Tablellsymbol darunter)
        > Wo holt denn der wizard die information her ?

    Der ermittelt die über Schema-Informationen aus der Datenbank. Nehmen wir mal an, die DB heisst "Frank" ;-)
    Versuche mal folgenden SQL SP-Code nur zum Test:

    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    CREATE PROCEDURE DemoProzedur
    AS
    BEGIN
    	SET NOCOUNT ON;
    	SELECT * FROM Person
    END
    GO
    
    Dann die von mir beschriebenen Aktionen durchführen. Dann sollte er automatisch folgenden Code ins Form1_Load einfügen:
     ' TODO: Diese Codezeile lädt Daten in die Tabelle "frankDataSet.DemoProzedur". Sie können sie bei Bedarf verschieben oder entfernen.
     Me.demoProzedurTableAdapter.Fill(Me.frankDataSet.DemoProzedur)
    
    


           > Was sollte denn unter dem DatsetIcon (Angezeigte  Datasources) angezeigt werden ?

    Dann steht im Datenquellen-Fenster: FrankDataSet und rechts verschoben darunter "DemoProzedur", dass links ein "+" Symbol hat, das aufklappbar ist (die Spalten enthält).


    ciao Frank

     

    Montag, 25. Oktober 2010 13:07