Avatar billede eerikk Nybegynder
19. februar 2004 - 12:50 Der er 30 kommentarer og
2 løsninger

SQL-klasse til identificering af table-attributter

Jeg sidder i VB.Net og laver C#-kode der skal lave noget database-interaktion. Det jeg vil er at give navnet på en table og så få attributterne tilbage. Har jeg feks. en table kaldet "ansat" som har attributterne "navn" og CPR-nr", så vil jeg give "ansat" og få "navn,CPR-nr" tilbage - men hvordan - jeg har via MSN ikke kunne finde en klasse der kan hjælpe... What to do?

-Erik
Avatar billede arne_v Ekspert
19. februar 2004 - 13:05 #1
Hvis du har en OleDbConnection så kan du kalde GetOleDbSchemaTable
og få oplysninger tilbage on felterne.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemdataoledboledbconnectionclassgetoledbschematabletopic.asp
Avatar billede eerikk Nybegynder
19. februar 2004 - 13:10 #2
eksempelkodebid?
Avatar billede eerikk Nybegynder
19. februar 2004 - 13:12 #3
Jeg kan ikke bruge SqlDataReader.GetSchemaTable vel?
Avatar billede burningice Nybegynder
19. februar 2004 - 13:14 #4
tja... så svært er det nu heller ikke... du får jo smidt en helt normal DataTable i hovedet, som er meget nem at arbejde med. DU kunne evt. gennemløbe alle kulonnerne og hente navnene ud på den måde:

DataTable dt = ditabel;

foreach(DataColumn dc in dt.Columns) {
  Response.Write(dc.ColumnName);
}
Avatar billede eerikk Nybegynder
19. februar 2004 - 13:21 #5
Nåeh ja - når jeg først har et DataTable, men hvordan får jeg det?

Man skriver ikke bare "Datatable forNemt = GetOleDbSchemaTable();" vel?
Avatar billede eerikk Nybegynder
19. februar 2004 - 13:22 #6
Kan vi tage den fra: Jeg har min "SqlConnection conn" og så....?? :o)
Avatar billede arne_v Ekspert
19. februar 2004 - 13:28 #7
SqlConnection har af uransagelige årsager ikke en GetSqlSchemaTable.

Mit gæt vil være at det er fordi SqlConnection jo kun er til SQLServer
og at man derfor kan bruge de SQLServer specifikke SQL sætninger til at hente
den information.
Avatar billede arne_v Ekspert
19. februar 2004 - 13:30 #8
Jo - du kan godt lave en SELECT * FROM tabel og så bruge GetSchemaTable på
den resulterende SqlDataReader.

Den returnerer præcis den samme information, men det er måske ikke
så elegant.
Avatar billede arne_v Ekspert
19. februar 2004 - 13:33 #9
SQLServer specifik kunne vær enoget a la:

            SqlCommand cmd = new SqlCommand("sp_columns", con);
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.Add("@table_name", "'TABLE'");
            SqlDataReader rdr = cmd.ExecuteReader();

som vil returnere felt navn i den fjerde kolonne (index 3).
Avatar billede eerikk Nybegynder
19. februar 2004 - 13:34 #10
Jeg bruger faktisk SQLServer - synes du det er mere elegangt at bruge sql-statements?
Avatar billede burningice Nybegynder
19. februar 2004 - 13:35 #11
tjo.. hvorfor ikke?

det ser ud til at det kun er OleDb der kan gøre det direkte på connection'en, ved SqlClient kan du gøre det på datareaderen:

DataTable forNemt = reader.GetSchemaTable();
Avatar billede eerikk Nybegynder
19. februar 2004 - 13:37 #12
Jeg prøver det - smid lige et svar i mellemtiden Arne V :o)
Avatar billede arne_v Ekspert
19. februar 2004 - 13:38 #13
Det er rent æstetisk at det generer mig at skulle lave en SELECT * query bare
for at skaffe feltnavnene.
Avatar billede arne_v Ekspert
19. februar 2004 - 13:38 #14
svar
Avatar billede arne_v Ekspert
19. februar 2004 - 13:39 #15
Jeg syne siøvrigt at MS burde være lidt konsistente og tilføje GetSqlSchemaTable.
Avatar billede burningice Nybegynder
19. februar 2004 - 13:50 #16
arne_v>> som du selv siger, så kommer det nok af at SqlClient er til direkte opkobling mod en MSSQL-server. Hvis du kigger på eksemplet på GetOleDbSchemaTable i SDK'et tager den nogle paremetre der filtrerer resultatet, og de ligner til forveksling de parametre som SPROC'en i MSSQL tager.

men jo, de kunne da godt have lavet en GetSqlSchemaTable, som egentlig laver det trick med at åbne en reader, execute SPROC'en og returnere readerens SchemaTable
Avatar billede eerikk Nybegynder
19. februar 2004 - 14:15 #17
Hvordan gennemløber jeg det DataTable jeg får??
Avatar billede arne_v Ekspert
19. februar 2004 - 14:19 #18
cyberfessor har beskrevet foreach løkken
Avatar billede arne_v Ekspert
19. februar 2004 - 14:20 #19
MSDN skriver:

      foreach(DataColumn myColumn in myTable.Columns){
          Console.WriteLine(myColumn.ColumnName);
      }
Avatar billede eerikk Nybegynder
19. februar 2004 - 15:11 #20
I stedet for værdierne jeg ønsker har første plads "Columnname", osv. Den løkke giver mig noget andet end navnet på tabellens attributter....
Avatar billede arne_v Ekspert
19. februar 2004 - 15:24 #21
Du har vel ikke kombineret stored procedure kaldet og reader.GetSchemaTable ?
Avatar billede arne_v Ekspert
19. februar 2004 - 15:25 #22
Det er enten SELECT * og reader.GetSchemaTable eller stored procedure og
reader[3] helt normalt.
Avatar billede eerikk Nybegynder
20. februar 2004 - 09:14 #23
Jeg gør følgende:

private ArrayList getTableColumns(String tableName)
        { 
            //Dan dynamisk datastruktur ArrayList, som indeholder column-names
            ArrayList ALcolumns = new ArrayList();

            //Dan DataTable der kan spejle den angivne table
            DataTable retrTable = new DataTable();

            //Lav DataTable-object ud fra modtaget String tableName
            try
            {
                conn.Open();
                SqlCommand sqlGetColumn = new SqlCommand(("SELECT * FROM "+tableName), conn);
                SqlDataReader tempReader = sqlGetColumn.ExecuteReader();
                retrTable = tempReader.GetSchemaTable();
                conn.Close();
            }
            catch(Exception exp)
            {
                MessageBox.Show(exp.ToString());
                return null;
            }
            catch
            {
                MessageBox.Show("Exception cast but not caught!");
                return null;
            }

            //Overfør Columns til ArrayList og trim/returner denne
            foreach(DataColumn dc in retrTable.Columns)
            {
                ALcolumns.Add(dc.ColumnName);
            }
            ALcolumns.TrimToSize();
            return ALcolumns;

        }
Avatar billede eerikk Nybegynder
20. februar 2004 - 09:20 #24
Første plads burde være "id" og anden burde være "text", men med ovenstående kode er første plads "ColumnName" og anden plads er "ColumnOrdinal"...!!

Det virker som om den har fået fat på navnene på nogle bestemte værdier i stedet for selve værdierne...
Avatar billede eerikk Nybegynder
20. februar 2004 - 09:27 #25
Den løber 23 gange igennem den foreach selvom der kun er 2 attributter i min table...
Avatar billede arne_v Ekspert
20. februar 2004 - 09:46 #26
Tilsyneladende får du hentet felt navnene for meta data, mens felt navnene i
query output er felt data i meta data.

Brug rdr.FieldCount og rdr.GetName(i) i.s.f..

Eksempel:

using System;
using System.Data;
using System.Data.SqlClient;

class MainClass
{
    public static void Main(string[] args)
    {
        SqlConnection con = new SqlConnection("server=ARNEPC2\\ARNEPC2RUN;Integrated Security=SSPI;database=TestMSDE");
        con.Open();
        SqlCommand sel = new SqlCommand("SELECT * FROM T1", con);
        SqlDataReader rdr = sel.ExecuteReader();
        for(int i = 0; i < rdr.FieldCount; i++)
        {
            Console.WriteLine(rdr.GetName(i));
        }
        while(rdr.Read()) {
            Console.WriteLine(rdr[0] + " " + rdr[1]);
        }
        rdr.Close();
        con.Close();
    }
}

Output:

F1
F2
1 A
2 BB
3 CCC
Avatar billede eerikk Nybegynder
20. februar 2004 - 09:56 #27
hmm men dette fejler (run-time err):

private ArrayList getTableColumns(String tableName)
        { 
            //Dan dynamisk datastruktur ArrayList, som indeholder column-names
            ArrayList ALcolumns = new ArrayList();

            //Dan DataTable der kan spejle den angivne table + reader
            DataTable retrTable;
            SqlDataReader tempReader;

            //Lav DataTable-object ud fra modtaget String tableName
            try
            {
                conn.Open();
                SqlCommand sqlGetColumn = new SqlCommand(("SELECT * FROM "+tableName), conn);
                tempReader = sqlGetColumn.ExecuteReader();
                retrTable = tempReader.GetSchemaTable();
                conn.Close();
            }
            catch(Exception exp)
            {
                MessageBox.Show(exp.ToString());
                return null;
            }
            catch
            {
                MessageBox.Show("Exception cast but not caught!");
                return null;
            }
           
            int testNum = 0;

            //Overfør Columns til ArrayList og trim/returner denne
            //foreach(DataColumn dc in retrTable.Columns)
            //{
            //    ALcolumns.Add(dc.ColumnName);
            //    testNum++;
            //}
            for(int i = 0; i < tempReader.FieldCount; i++)
            {
                Console.WriteLine(tempReader.GetName(i));
            }
            while(tempReader.Read())
            {
                Console.WriteLine(tempReader[0] + " " + tempReader[1]);
            }
            tempReader.Close();
            ALcolumns.TrimToSize();
            MessageBox.Show("Antal gennemløb: "+testNum.ToString());
            return ALcolumns;

        }
Avatar billede eerikk Nybegynder
20. februar 2004 - 09:59 #28
An unhandled exception of type 'System.InvalidOperationException' occurred in system.data.dll

Additional information: Invalid attempt to FieldCount when reader is closed
Avatar billede eerikk Nybegynder
20. februar 2004 - 10:06 #29
ups - fejl i min kode med hvor conn lukkes og hvilke dele der skal ind i try/catch :o) Nu funker det :o)

Et sidste tip om hvordan jeg så får at vide hvilken datatype hver column har :o)
Avatar billede eerikk Nybegynder
20. februar 2004 - 10:07 #30
Måske dtatypeName? :o)
Avatar billede arne_v Ekspert
20. februar 2004 - 11:56 #31
Tja - det lyder som noget af det rigtige !
Avatar billede eerikk Nybegynder
20. februar 2004 - 12:31 #32
Tak for hjælpen Arne - det funker altsammen nu :o)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester