locked
große Menge Tabellen-Daten an Excel zum Editieren übergeben. RRS feed

  • Frage

  • Hallo,

    der Kunde bekommt große Listen von Daten in Excel geliefert und möchte sie über Excel in eine Liste in ein C#-Programm übergeben.

    Auch soll das andersherum gehen: eine große Liste vom  BindingList< Typx> wir in einem Gridview angezeigt und soll ggf, an Excel zum weiter bearbeiten übergeben werden und wenn man in Excel fertig ist, sollen die Daten wieder zurück in die BindingList< Typx> und in einem DataGridView angezeigt werden.

    Die Übergabe an Excel bekomme ich zwar hin, ggf, auch die Rückgabe, aber das dauert ewig. 

    Kann man das beschleunigen?

    Danke

    Montag, 26. November 2018 18:38

Alle Antworten

  • Hi,
    es gibt immer Möglichkeiten einer Beschleunigung. Dazu müsste man aber wissen, was Du konkret machst und am besten noch, wo in Deinem Algorithmus die Zeit verbraten wird. Typische Verdächtige sind Select und Activate bei Nutzung des Objektmodells oder eine fehlende schema.ini bei Nutzung der Jet.

    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP für Developer Technologies)
    Meine Homepage mit Tipps und Tricks

    Montag, 26. November 2018 19:03
  • Hi,

    in meinem Programm werden die Daten in Form von BindingList< Typx> gehalten und irgendwohin serialisiert.

    Das sin aber Daten, die erstmal in Form von irgendwie formatierten Text von Kunden geliefert werden.

    Zum Import wollte ich Excel nutzen, wo der User (nicht der Kunde und Datenlieferant) die Daten aufbereiten kann.

    Also von Excel übernehmen.

    ---------

    anderer Fall:

    Die Daten sind schon im Programm. Der User will sie ändern.

    Dazu sollen die Daten wieder an Excel übergeben werden - in Excel werden sie bearbeitet, Excel geschlossen und mein Programm übernimmt die Daten - so der Wunsch um nicht alles selber programmieren zu müssen.

    Allerdings dauert das bei 1000 Zeilen schon sehr lange.

    Ich wäre dankbar für eine bessere Idee.


    Montag, 26. November 2018 22:06
  • Hi,

    man kann Exceldaten über OleDbConnection auch direkt lesen und schreiben. In der Regel ist das erheblich schneller als zu versuchen, sie einzulesen, zu transformieren und auf irgendeinem Weg dann wieder zu schreiben.

    Da Du nicht schreibst, wie Du das bisher machst, hier erstmal ein generelles Beispiel:

      Read and Write Excel Documents Using OLEDB


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
    https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, Remotesupport

    Montag, 26. November 2018 22:20
    Moderator
  • Hi,
    das Schreiben von 1000 Zeilen mit 50 Spalten in eine csv-Datei dauert in meiner Demo nur 27 ms. Hier mal die Demo.

    Imports System.IO
    
    Module Module42
      Sub Main()
        Try
          Dim c As New Demo
          c.Execute()
        Catch ex As Exception
          Console.WriteLine(ex.Message)
        End Try
        Console.WriteLine("weiter mit Taste")
        Console.ReadKey()
      End Sub
    
      Friend Class Demo
        Private fileName As String = "c:\temp\x.csv"
    
        Friend Sub Execute()
          Dim sw As New Stopwatch
          sw.Start()
          Using wrt As New StreamWriter(fileName)
            For i = 1 To 1000
              For k = 1 To 50
                wrt.Write($"Zelle {i} {k}")
              Next
              wrt.WriteLine()
            Next
          End Using
          sw.Stop()
          Console.WriteLine($"Export-Dauer {sw.ElapsedMilliseconds} ms")
        End Sub
    
      End Class
    
    End Module

    Dasselbe mit Objektautomatisierung für 1000 Zeilen mit 50 Spalten in 50000 Einzelzellen dauert 140 Sekunden:

    Imports Microsoft.Office.Interop
    
    Module Module43
      Sub Main()
        Try
          Dim c As New Demo
          c.Execute()
        Catch ex As Exception
          Console.WriteLine(ex.Message)
        End Try
        Console.WriteLine("weiter mit Taste")
        Console.ReadKey()
      End Sub
    
      Friend Class Demo
        Private fileName As String = "c:\temp\x.xlsx"
    
        Friend Sub Execute()
          Dim sw As New Stopwatch
          sw.Start()
          Dim xlApp As New Excel.Application
          Dim xlWb As Excel.Workbook = xlApp.Workbooks.Add()
          Dim xlSh As Excel.Worksheet = CType(xlWb.Worksheets(1), Excel.Worksheet)
          For i = 1 To 1000
            For k = 1 To 50
              xlSh.Cells(i, k) = $"Zelle {i} {k}"
            Next
          Next
          xlWb.SaveAs(fileName)
          xlWb.Close()
          xlApp = Nothing
          sw.Stop()
          Console.WriteLine($"Export-Dauer {sw.ElapsedMilliseconds} ms")
        End Sub
    
      End Class
    
    End Module
    Wenn man in den 50000 Zellen mit der Objektautomatisierung nur 50 Zellinhalte ändert, dann dauert das incl. Datei Öffnen und Speichern nur 7 Sekunden.


    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP für Developer Technologies)
    Meine Homepage mit Tipps und Tricks



    Dienstag, 27. November 2018 06:09
  • Hi,

    man kann Exceldaten über OleDbConnection auch direkt lesen und schreiben. In der Regel ist das erheblich schneller als zu versuchen, sie einzulesen, zu transformieren und auf irgendeinem Weg dann wieder zu schreiben.


    Ok, Vielen Dank, das ist schonmal schweine-schnell ...

    Bisher wurde es über Interop.Excel gemacht, die Zellen einzeln gelesen und ausgewertet, aber auch bei einem Fehler wieder in Excel angezeigt wo der Fehler liegt.

    Nur dauert das eben ewig bei 1000 und mehr Zeilen

    MfG

    Dienstag, 27. November 2018 08:17
  • Hi,
    hier mal eine kleine Demo, in der 1000 Zeilen mit 50 Spalten in einer Excel-Tabelle mit OleDb erzeugt werden. Das dauert bei mir mit 8 Sekunden:

    Imports System.Data.OleDb
    Imports System.IO
    Imports Microsoft.Office.Interop
    
    Module Module44
      Sub Main()
        Try
          Dim c As New Demo
          c.Execute()
        Catch ex As Exception
          Console.WriteLine(ex.Message)
        End Try
        Console.WriteLine("weiter mit Taste")
        Console.ReadKey()
      End Sub
    
      Friend Class Demo
        Private fileName As String = "c:\temp\x.xlsx"
        Private cnString As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=""Excel 12.0 Xml;HDR=YES"";"
        Friend Sub Execute()
          ' Vorbereitung einer leeren Tabelle
          File.Delete(fileName)
          Dim xlApp As New Excel.Application
          Dim xlWb As Excel.Workbook = xlApp.Workbooks.Add
          Dim xlSh As Excel.Worksheet = CType(xlWb.Worksheets(1), Excel.Worksheet)
          xlSh.Cells(1, 1) = $"ID"
          For i = 2 To 50
            xlSh.Cells(1, i) = $"Spalte{i:00}"
          Next
          xlWb.SaveAs(fileName)
          xlWb.Close()
          xlApp = Nothing
          ' Messung des Zugriffes
          Dim sw As New Stopwatch
          sw.Start()
          Dim dt As New DataTable
          Using cn As New OleDbConnection(String.Format(cnString, fileName))
            Using da As New OleDbDataAdapter("SELECT * FROM [Tabelle1$]", cn)
              da.Fill(dt)
              With dt.Columns(0)
                .AutoIncrement = True
                .AutoIncrementSeed = 1
                .AutoIncrementStep = 1
              End With
              For i = 1 To 1000
                Dim r = dt.NewRow
                For k = 1 To 49
                  r(k) = $"Zelle {i} {k}"
                Next
                dt.Rows.Add(r)
              Next
              Dim cb As New OleDbCommandBuilder(da)
              cb.QuotePrefix = "["
              cb.QuoteSuffix = "]"
              da.Update(dt)
            End Using
          End Using
          sw.Stop()
          Console.WriteLine($"Export-Dauer {sw.ElapsedMilliseconds} ms")
        End Sub
    
      End Class
    
    End Module


    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP für Developer Technologies)
    Meine Homepage mit Tipps und Tricks


    Dienstag, 27. November 2018 08:22
  • Hallo zusammen,

    direkt mit INSERT, UPDATE Statements geht das erheblich schneller über OleDb:

    class Program
    {
        static void Main(string[] args)
        {
            WriteExcel();
            Console.WriteLine( "" );
            WriteExcel2();
            Console.WriteLine( "" );
            WriteExcel();
            Console.WriteLine( "" );
            WriteExcel2();
    
            Console.ReadKey();
        }
    
        static void WriteExcel()
        {
            Console.WriteLine( $"Start: {DateTime.Now.ToString( "dd.MM.yyyy HH:mm:ss.ffff" )}" );
    
            String connString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=X:\Ordner\Test.xlsx;Extended Properties=""Excel 12.0 Xml;HDR=YES"";";
            String sqlStatement = String.Empty;
    
            using( OleDbConnection conn = new OleDbConnection( connString ) ) {
                conn.Open();
                using( OleDbCommand cmd = new OleDbCommand( String.Empty, conn ) ) {
                    for( int i = 1; i <= 1000; i++ ) {
                        String iAsString = i.ToString();
                        sqlStatement = $@"INSERT INTO [Tabelle1$] ( [ID], [Name], [Value] ) VALUES ( {iAsString}, 'Name {iAsString}', 'Wert {iAsString}' )";
                        cmd.CommandText = sqlStatement;
                        cmd.ExecuteNonQuery();
                    }
                }
                conn.Close();
            }
    
            Console.WriteLine( $"Ende: {DateTime.Now.ToString( "dd.MM.yyyy HH:mm:ss.ffff" )}" );
        }
    
        static void WriteExcel2()
        {
            Console.WriteLine( $"Start: {DateTime.Now.ToString( "dd.MM.yyyy HH:mm:ss.ffff" )}" );
    
            String connString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=X:\Ordner\Test.xlsx;Extended Properties=""Excel 12.0 Xml;HDR=YES"";";
            String sqlStatement = String.Empty;
    
            using( OleDbConnection conn = new OleDbConnection( connString ) ) {
                conn.Open();
                using( OleDbCommand cmd = new OleDbCommand( String.Empty, conn ) ) {
                    cmd.CommandText = $@"INSERT INTO [Tabelle1$] ( [ID], [Name], [Value] ) VALUES ( ?, ?, ? )";
                    cmd.Parameters.AddWithValue( "@ID", 0 );
                    cmd.Parameters.AddWithValue( "@Name", "" );
                    cmd.Parameters.AddWithValue( "@Value", "" );
    
                    for( int i = 1; i <= 1000; i++ ) {
                        String iAsString = i.ToString();
                        cmd.Parameters["@ID"].Value    = iAsString;
                        cmd.Parameters["@Name"].Value  = "Name " + iAsString;
                        cmd.Parameters["@Value"].Value = "Wert " + iAsString;
                        cmd.ExecuteNonQuery();
                    }
                }
                conn.Close();
            }
    
            Console.WriteLine( $"Ende: {DateTime.Now.ToString( "dd.MM.yyyy HH:mm:ss.ffff" )}" );
        }
    }

    Der allererste Lauf braucht etwas länger, ich nehme an, weil die Exceldatei erst geöffnet werden muss. Die Zeiten bei mir sind in der Regel in etwa wie folgt:

    Start: 27.11.2018 09:43:01.2051
    Ende : 27.11.2018 09:43:02.6479
    
    Start: 27.11.2018 09:43:02.6489
    Ende : 27.11.2018 09:43:03.0822
    
    Start: 27.11.2018 09:43:03.0832
    Ende : 27.11.2018 09:43:03.4620
    
    Start: 27.11.2018 09:43:03.4620
    Ende : 27.11.2018 09:43:03.8911

    Ab dem zweiten Durchlauf ca. 400 ms für jeweils 1000 Datensätze mit 3 Spalten. Aber auch mit 50 Spalten sollte es nur unwesentlich langsamer sein.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
    https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, Remotesupport


    Dienstag, 27. November 2018 08:48
    Moderator
  • Hi Stefan,
    mit nur 3 Spalten geht das natürlich viel schneller als mein Beispiel mit 50 Spalten. Außerdem ist bei der Arbeit ohne Datenpuffer für das GridView nur die Nutzung von INSERT und UPDATE mit mehr Aufwand verbunden als die Nutzung z.B. einer DataTable wie in meinem Beispiel. Letztendlich muss aber der Anwendungsprogrammierer auf Basis der Aufgabenstellung entscheiden, welche Technologie am besten passt.

    Meine Messungen ergeben, dass es mit separaten INSERT's 1 Sekunde länger (8 Sekunden) dauert als mit dem CommandBuilder und einer DataTable bei gleicher Datenmenge (1000 Sätze mit 50 Spalten).

    Imports System.Data.OleDb
    Imports System.IO
    Imports Microsoft.Office.Interop
    
    Module Module45
      Sub Main()
        Try
          Dim c As New Demo
          c.Execute()
        Catch ex As Exception
          Console.WriteLine(ex.Message)
        End Try
        Console.WriteLine("weiter mit Taste")
        Console.ReadKey()
      End Sub
    
      Friend Class Demo
        Private fileName As String = "c:\temp\x.xlsx"
        Private cnString As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=""Excel 12.0 Xml;HDR=YES"";"
        Friend Sub Execute()
          ' Vorbereitung einer leeren Tabelle
          File.Delete(fileName)
          Dim xlApp As New Excel.Application
          Dim xlWb As Excel.Workbook = xlApp.Workbooks.Add
          Dim xlSh As Excel.Worksheet = CType(xlWb.Worksheets(1), Excel.Worksheet)
          For i = 1 To 50
            xlSh.Cells(1, i) = $"Spalte{i:00}"
          Next
          xlWb.SaveAs(fileName)
          xlWb.Close()
          xlApp = Nothing
          ' Messung des Zugriffes
          Dim sw As New Stopwatch
          sw.Start()
          Using cn As New OleDbConnection(String.Format(cnString, fileName))
            Using cmd As New OleDbCommand("", cn)
              Dim cmdText As String = "INSERT INTO [Tabelle1$] ({0}) VALUES ({1})"
              Dim cmdText1(49) As String
              Dim cmdText2(49) As String
              For i = 0 To 49
                cmdText1(i) = $"Spalte{i + 1:00}"
                cmdText2(i) = "?"
                cmd.Parameters.Add($"Par{i + 1:00}", OleDbType.VarWChar)
              Next
              cmd.CommandText = String.Format(cmdText, String.Join(",", cmdText1), String.Join(",", cmdText2))
              cn.Open()
              For i = 1 To 1000
                For k = 0 To 49
                  cmd.Parameters(k).Value = $"Zelle {i} {k}"
                Next
                cmd.ExecuteNonQuery()
              Next
            End Using
          End Using
          sw.Stop()
          Console.WriteLine($"Export-Dauer {sw.ElapsedMilliseconds} ms")
        End Sub
    
      End Class
    
    End Module


    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP für Developer Technologies)
    Meine Homepage mit Tipps und Tricks

    Dienstag, 27. November 2018 10:03
  • Hallo Peter,

    unsere Codebeispiele sind natürlich nicht direkt vergleichbar. Folgendes ist im Release mit ca. 1,5 bis 3 Sekunden durch. Im Debugmodus dauert es ungefähr 4 bis 7 Sekunden.

    Die Variante mit den OleDbParametern dauert bei mir zwischen 2,5 und 4 Sekunden im Release und zwischen 4 und 8 Sekunden im Debug, wobei es natürlich auch auf die bisherigen Inhalte der Exceldatei ankommt. Wenn dort schon zigtausende Datensätze drinstehen, dauert es etwas länger, die Datei zu schreiben.

    Aber wie Du schon geschrieben hast: Es ist nun am TE, zu entscheiden, was für ihn das Beste wäre und ob eine der genannten Optionen für ihn in Frage kommt.

    class Program
    {
        static void Main(string[] args)
        {
            WriteExcel();
    
            Console.WriteLine( "Press the any key to continue: " );
            Console.ReadKey();
        }
    
        static void WriteExcel()
        {
            Console.WriteLine( $"Start: {DateTime.Now.ToString( "dd.MM.yyyy HH:mm:ss.ffff" )}" );
    
            String connString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=X:\Ordner\Test.xlsx;Extended Properties=""Excel 12.0 Xml;HDR=YES"";";
            String sqlStatement = String.Empty;
    
            using( OleDbConnection conn = new OleDbConnection( connString ) ) {
                conn.Open();
                using( OleDbCommand cmd = new OleDbCommand( String.Empty, conn ) ) {
                    for( int i = 1; i <= 1000; i++ ) {
                        String iAsString = i.ToString();
                        sqlStatement = $@"INSERT INTO [Tabelle1$] ( [ID], [Name], [Value], [Spalte4], [Spalte5], [Spalte6], [Spalte7], [Spalte8], [Spalte9], [Spalte10], [Spalte11], [Spalte12], [Spalte13], [Spalte14], [Spalte15], [Spalte16], [Spalte17], [Spalte18], [Spalte19], [Spalte20], [Spalte21], [Spalte22], [Spalte23], [Spalte24], [Spalte25], [Spalte26], [Spalte27], [Spalte28], [Spalte29], [Spalte30], [Spalte31], [Spalte32], [Spalte33], [Spalte34], [Spalte35], [Spalte36], [Spalte37], [Spalte38], [Spalte39], [Spalte40], [Spalte41], [Spalte42], [Spalte43], [Spalte44], [Spalte45], [Spalte46], [Spalte47], [Spalte48], [Spalte49], [Spalte50] ) VALUES ( {iAsString}, 'Name {iAsString}', 'Wert {iAsString}', 'Spalte4 {iAsString}', 'Spalte5 {iAsString}', 'Spalte6 {iAsString}', 'Spalte7 {iAsString}', 'Spalte8 {iAsString}', 'Spalte9 {iAsString}', 'Spalte10 {iAsString}', 'Spalte11 {iAsString}', 'Spalte12 {iAsString}', 'Spalte13 {iAsString}', 'Spalte14 {iAsString}', 'Spalte15 {iAsString}', 'Spalte16 {iAsString}', 'Spalte17 {iAsString}', 'Spalte18 {iAsString}', 'Spalte19 {iAsString}', 'Spalte20 {iAsString}', 'Spalte21 {iAsString}', 'Spalte22 {iAsString}', 'Spalte23 {iAsString}', 'Spalte24 {iAsString}', 'Spalte25 {iAsString}', 'Spalte26 {iAsString}', 'Spalte27 {iAsString}', 'Spalte28 {iAsString}', 'Spalte29 {iAsString}', 'Spalte30 {iAsString}', 'Spalte31 {iAsString}', 'Spalte32 {iAsString}', 'Spalte33 {iAsString}', 'Spalte34 {iAsString}', 'Spalte35 {iAsString}', 'Spalte36 {iAsString}', 'Spalte37 {iAsString}', 'Spalte38 {iAsString}', 'Spalte39 {iAsString}', 'Spalte40 {iAsString}', 'Spalte41 {iAsString}', 'Spalte42 {iAsString}', 'Spalte43 {iAsString}', 'Spalte44 {iAsString}', 'Spalte45 {iAsString}', 'Spalte46 {iAsString}', 'Spalte47 {iAsString}', 'Spalte48 {iAsString}', 'Spalte49 {iAsString}', 'Spalte50 {iAsString}' )";
                        cmd.CommandText = sqlStatement;
                        cmd.ExecuteNonQuery();
                    }
                }
                conn.Close();
            }
    
            Console.WriteLine( $"Ende: {DateTime.Now.ToString( "dd.MM.yyyy HH:mm:ss.ffff" )}" );
        }
    
        static void WriteExcel2()
        {
            Console.WriteLine( $"Start: {DateTime.Now.ToString( "dd.MM.yyyy HH:mm:ss.ffff" )}" );
    
            String connString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=X:\Ordner\Test.xlsx;Extended Properties=""Excel 12.0 Xml;HDR=YES"";";
            String sqlStatement = String.Empty;
    
            using( OleDbConnection conn = new OleDbConnection( connString ) ) {
                conn.Open();
                using( OleDbCommand cmd = new OleDbCommand( String.Empty, conn ) ) {
                    cmd.CommandText = $@"INSERT INTO [Tabelle1$] ( [ID], [Name], [Value], [Spalte4], [Spalte5], [Spalte6], [Spalte7], [Spalte8], [Spalte9], [Spalte10], [Spalte11], [Spalte12], [Spalte13], [Spalte14], [Spalte15], [Spalte16], [Spalte17], [Spalte18], [Spalte19], [Spalte20], [Spalte21], [Spalte22], [Spalte23], [Spalte24], [Spalte25], [Spalte26], [Spalte27], [Spalte28], [Spalte29], [Spalte30], [Spalte31], [Spalte32], [Spalte33], [Spalte34], [Spalte35], [Spalte36], [Spalte37], [Spalte38], [Spalte39], [Spalte40], [Spalte41], [Spalte42], [Spalte43], [Spalte44], [Spalte45], [Spalte46], [Spalte47], [Spalte48], [Spalte49], [Spalte50] ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )";
                    cmd.Parameters.AddWithValue( "@ID", 0 );
                    cmd.Parameters.AddWithValue( "@Name", "" );
                    cmd.Parameters.AddWithValue( "@Value", "" );
                    cmd.Parameters.AddWithValue( "@Spalte4", "" );
                    cmd.Parameters.AddWithValue( "@Spalte5", "" );
                    cmd.Parameters.AddWithValue( "@Spalte6", "" );
                    cmd.Parameters.AddWithValue( "@Spalte7", "" );
                    cmd.Parameters.AddWithValue( "@Spalte8", "" );
                    cmd.Parameters.AddWithValue( "@Spalte9", "" );
                    cmd.Parameters.AddWithValue( "@Spalte10", "" );
                    cmd.Parameters.AddWithValue( "@Spalte11", "" );
                    cmd.Parameters.AddWithValue( "@Spalte12", "" );
                    cmd.Parameters.AddWithValue( "@Spalte13", "" );
                    cmd.Parameters.AddWithValue( "@Spalte14", "" );
                    cmd.Parameters.AddWithValue( "@Spalte15", "" );
                    cmd.Parameters.AddWithValue( "@Spalte16", "" );
                    cmd.Parameters.AddWithValue( "@Spalte17", "" );
                    cmd.Parameters.AddWithValue( "@Spalte18", "" );
                    cmd.Parameters.AddWithValue( "@Spalte19", "" );
                    cmd.Parameters.AddWithValue( "@Spalte20", "" );
                    cmd.Parameters.AddWithValue( "@Spalte21", "" );
                    cmd.Parameters.AddWithValue( "@Spalte22", "" );
                    cmd.Parameters.AddWithValue( "@Spalte23", "" );
                    cmd.Parameters.AddWithValue( "@Spalte24", "" );
                    cmd.Parameters.AddWithValue( "@Spalte25", "" );
                    cmd.Parameters.AddWithValue( "@Spalte26", "" );
                    cmd.Parameters.AddWithValue( "@Spalte27", "" );
                    cmd.Parameters.AddWithValue( "@Spalte28", "" );
                    cmd.Parameters.AddWithValue( "@Spalte29", "" );
                    cmd.Parameters.AddWithValue( "@Spalte30", "" );
                    cmd.Parameters.AddWithValue( "@Spalte31", "" );
                    cmd.Parameters.AddWithValue( "@Spalte32", "" );
                    cmd.Parameters.AddWithValue( "@Spalte33", "" );
                    cmd.Parameters.AddWithValue( "@Spalte34", "" );
                    cmd.Parameters.AddWithValue( "@Spalte35", "" );
                    cmd.Parameters.AddWithValue( "@Spalte36", "" );
                    cmd.Parameters.AddWithValue( "@Spalte37", "" );
                    cmd.Parameters.AddWithValue( "@Spalte38", "" );
                    cmd.Parameters.AddWithValue( "@Spalte39", "" );
                    cmd.Parameters.AddWithValue( "@Spalte40", "" );
                    cmd.Parameters.AddWithValue( "@Spalte41", "" );
                    cmd.Parameters.AddWithValue( "@Spalte42", "" );
                    cmd.Parameters.AddWithValue( "@Spalte43", "" );
                    cmd.Parameters.AddWithValue( "@Spalte44", "" );
                    cmd.Parameters.AddWithValue( "@Spalte45", "" );
                    cmd.Parameters.AddWithValue( "@Spalte46", "" );
                    cmd.Parameters.AddWithValue( "@Spalte47", "" );
                    cmd.Parameters.AddWithValue( "@Spalte48", "" );
                    cmd.Parameters.AddWithValue( "@Spalte49", "" );
                    cmd.Parameters.AddWithValue( "@Spalte50", "" );
    
                    for( int i = 1; i <= 1000; i++ ) {
                        String iAsString = i.ToString();
                        cmd.Parameters["@ID"].Value       = iAsString;
                        cmd.Parameters["@Name"].Value     = "Name " + iAsString;
                        cmd.Parameters["@Value"].Value    = "Wert " + iAsString;
                        cmd.Parameters["@Spalte4"].Value  = "Spalte 4 " + iAsString;
                        cmd.Parameters["@Spalte5"].Value  = "Spalte 5 " + iAsString;
                        cmd.Parameters["@Spalte6"].Value  = "Spalte 6 " + iAsString;
                        cmd.Parameters["@Spalte7"].Value  = "Spalte 7 " + iAsString;
                        cmd.Parameters["@Spalte8"].Value  = "Spalte 8 " + iAsString;
                        cmd.Parameters["@Spalte9"].Value  = "Spalte 9 " + iAsString;
                        cmd.Parameters["@Spalte10"].Value = "Spalte 10 " + iAsString;
                        cmd.Parameters["@Spalte11"].Value = "Spalte 11 " + iAsString;
                        cmd.Parameters["@Spalte12"].Value = "Spalte 12 " + iAsString;
                        cmd.Parameters["@Spalte13"].Value = "Spalte 13 " + iAsString;
                        cmd.Parameters["@Spalte14"].Value = "Spalte 14 " + iAsString;
                        cmd.Parameters["@Spalte15"].Value = "Spalte 15 " + iAsString;
                        cmd.Parameters["@Spalte16"].Value = "Spalte 16 " + iAsString;
                        cmd.Parameters["@Spalte17"].Value = "Spalte 17 " + iAsString;
                        cmd.Parameters["@Spalte18"].Value = "Spalte 18 " + iAsString;
                        cmd.Parameters["@Spalte19"].Value = "Spalte 29 " + iAsString;
                        cmd.Parameters["@Spalte20"].Value = "Spalte 20 " + iAsString;
                        cmd.Parameters["@Spalte21"].Value = "Spalte 21 " + iAsString;
                        cmd.Parameters["@Spalte22"].Value = "Spalte 22 " + iAsString;
                        cmd.Parameters["@Spalte23"].Value = "Spalte 23 " + iAsString;
                        cmd.Parameters["@Spalte24"].Value = "Spalte 24 " + iAsString;
                        cmd.Parameters["@Spalte25"].Value = "Spalte 25 " + iAsString;
                        cmd.Parameters["@Spalte26"].Value = "Spalte 26 " + iAsString;
                        cmd.Parameters["@Spalte27"].Value = "Spalte 27 " + iAsString;
                        cmd.Parameters["@Spalte28"].Value = "Spalte 28 " + iAsString;
                        cmd.Parameters["@Spalte29"].Value = "Spalte 39 " + iAsString;
                        cmd.Parameters["@Spalte30"].Value = "Spalte 30 " + iAsString;
                        cmd.Parameters["@Spalte31"].Value = "Spalte 31 " + iAsString;
                        cmd.Parameters["@Spalte32"].Value = "Spalte 32 " + iAsString;
                        cmd.Parameters["@Spalte33"].Value = "Spalte 33 " + iAsString;
                        cmd.Parameters["@Spalte34"].Value = "Spalte 34 " + iAsString;
                        cmd.Parameters["@Spalte35"].Value = "Spalte 35 " + iAsString;
                        cmd.Parameters["@Spalte36"].Value = "Spalte 36 " + iAsString;
                        cmd.Parameters["@Spalte37"].Value = "Spalte 37 " + iAsString;
                        cmd.Parameters["@Spalte38"].Value = "Spalte 38 " + iAsString;
                        cmd.Parameters["@Spalte39"].Value = "Spalte 49 " + iAsString;
                        cmd.Parameters["@Spalte40"].Value = "Spalte 40 " + iAsString;
                        cmd.Parameters["@Spalte41"].Value = "Spalte 41 " + iAsString;
                        cmd.Parameters["@Spalte42"].Value = "Spalte 42 " + iAsString;
                        cmd.Parameters["@Spalte43"].Value = "Spalte 43 " + iAsString;
                        cmd.Parameters["@Spalte44"].Value = "Spalte 44 " + iAsString;
                        cmd.Parameters["@Spalte45"].Value = "Spalte 45 " + iAsString;
                        cmd.Parameters["@Spalte46"].Value = "Spalte 46 " + iAsString;
                        cmd.Parameters["@Spalte47"].Value = "Spalte 47 " + iAsString;
                        cmd.Parameters["@Spalte48"].Value = "Spalte 48 " + iAsString;
                        cmd.Parameters["@Spalte49"].Value = "Spalte 49 " + iAsString;
                        cmd.Parameters["@Spalte50"].Value = "Spalte 50 " + iAsString;
                        cmd.ExecuteNonQuery();
                    }
                }
                conn.Close();
            }
    
            Console.WriteLine( $"Ende: {DateTime.Now.ToString( "dd.MM.yyyy HH:mm:ss.ffff" )}" );
        }
    }


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
    https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, Remotesupport


    Dienstag, 27. November 2018 11:59
    Moderator
  • Hi, 

    ich bin ja OpenXML- Fan. Vor allem was Geschwindigkeit betrifft, ist das eine Überlegung wert.

    Hier mal eine kleine Deme (1000x50):

    using System;
    
    namespace OpenXMLSample
    {
        class Program
        {
            static void Main(string[] args)
            {
                Report report = new Report();
    
                report.CreateExcelDoc(@"C:\Temp\Report1.xlsx");
                Console.WriteLine("Excel file has created!");
                Console.ReadLine();
    
            }
        }
    }
    

    using System;
    using System.Collections.Generic;
    
    namespace OpenXMLSample
    {
        public class Employee
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public DateTime DOB { get; set; }
            public decimal Salary { get; set; }
    
            public string Spalte05 { get; set; }
            public string Spalte06 { get; set; }
            public string Spalte07 { get; set; }
            public string Spalte08 { get; set; }
            public string Spalte09 { get; set; }
            public string Spalte10 { get; set; }
            public string Spalte11 { get; set; }
            public string Spalte12 { get; set; }
            public string Spalte13 { get; set; }
            public string Spalte14 { get; set; }
            public string Spalte15 { get; set; }
            public string Spalte16 { get; set; }
            public string Spalte17 { get; set; }
            public string Spalte18 { get; set; }
            public string Spalte19 { get; set; }
            public string Spalte20 { get; set; }
            public string Spalte21 { get; set; }
            public string Spalte22 { get; set; }
            public string Spalte23 { get; set; }
            public string Spalte24 { get; set; }
            public string Spalte25 { get; set; }
            public string Spalte26 { get; set; }
            public string Spalte27 { get; set; }
            public string Spalte28 { get; set; }
            public string Spalte29 { get; set; }
            public string Spalte30 { get; set; }
            public string Spalte31 { get; set; }
            public string Spalte32 { get; set; }
            public string Spalte33 { get; set; }
            public string Spalte34 { get; set; }
            public string Spalte35 { get; set; }
            public string Spalte36 { get; set; }
            public string Spalte37 { get; set; }
            public string Spalte38 { get; set; }
            public string Spalte39 { get; set; }
            public string Spalte40 { get; set; }
            public string Spalte41 { get; set; }
            public string Spalte42 { get; set; }
            public string Spalte43 { get; set; }
            public string Spalte44 { get; set; }
            public string Spalte45 { get; set; }
            public string Spalte46 { get; set; }
            public string Spalte47 { get; set; }
            public string Spalte48 { get; set; }
            public string Spalte49 { get; set; }
            public string Spalte50 { get; set; }
    
        }
    
        public sealed class Employees
        {
            static List<Employee> _employees;
            const int COUNT = 1000;
    
            public static List<Employee> EmployeesList {
                private set { }
                get
                {
                    return _employees;
                }
            }
    
            static Employees()
            {
                Initialize();
            }
    
            private static void Initialize()
            {
                _employees = new List<Employee>();
    
                Random random = new Random();
    
                for (int i = 0; i < COUNT; i++)
                {
                    _employees.Add(new Employee()
                    {
                        Id = i,
                        Name = "Employee " + i,
                        DOB = new DateTime(1999, 1, 1).AddMonths(i),
                        Salary = random.Next(100, 10000),
    
                        Spalte05= random.Next(100, 10000).ToString(),
                        Spalte06= random.Next(100, 10000).ToString(),
                        Spalte07= random.Next(100, 10000).ToString(),
                        Spalte08= random.Next(100, 10000).ToString(),
                        Spalte09= random.Next(100, 10000).ToString(),
                        Spalte10= random.Next(100, 10000).ToString(),
                        Spalte11= random.Next(100, 10000).ToString(),
                        Spalte12= random.Next(100, 10000).ToString(),
                        Spalte13= random.Next(100, 10000).ToString(),
                        Spalte14= random.Next(100, 10000).ToString(),
                        Spalte15= random.Next(100, 10000).ToString(),
                        Spalte16= random.Next(100, 10000).ToString(),
                        Spalte17= random.Next(100, 10000).ToString(),
                        Spalte18= random.Next(100, 10000).ToString(),
                        Spalte19= random.Next(100, 10000).ToString(),
                        Spalte20 = random.Next(100, 10000).ToString(),
                        Spalte21 = random.Next(100, 10000).ToString(),
                        Spalte22 = random.Next(100, 10000).ToString(),
                        Spalte23 = random.Next(100, 10000).ToString(),
                        Spalte24 = random.Next(100, 10000).ToString(),
                        Spalte25 = random.Next(100, 10000).ToString(),
                        Spalte26 = random.Next(100, 10000).ToString(),
                        Spalte27 = random.Next(100, 10000).ToString(),
                        Spalte28 = random.Next(100, 10000).ToString(),
                        Spalte29 = random.Next(100, 10000).ToString(),
                        Spalte30 = random.Next(100, 10000).ToString(),
                        Spalte31 = random.Next(100, 10000).ToString(),
                        Spalte32 = random.Next(100, 10000).ToString(),
                        Spalte33 = random.Next(100, 10000).ToString(),
                        Spalte34 = random.Next(100, 10000).ToString(),
                        Spalte35 = random.Next(100, 10000).ToString(),
                        Spalte36 = random.Next(100, 10000).ToString(),
                        Spalte37 = random.Next(100, 10000).ToString(),
                        Spalte38 = random.Next(100, 10000).ToString(),
                        Spalte39 = random.Next(100, 10000).ToString(),
                        Spalte40 = random.Next(100, 10000).ToString(),
                        Spalte41 = random.Next(100, 10000).ToString(),
                        Spalte42 = random.Next(100, 10000).ToString(),
                        Spalte43 = random.Next(100, 10000).ToString(),
                        Spalte44 = random.Next(100, 10000).ToString(),
                        Spalte45 = random.Next(100, 10000).ToString(),
                        Spalte46 = random.Next(100, 10000).ToString(),
                        Spalte47 = random.Next(100, 10000).ToString(),
                        Spalte48 = random.Next(100, 10000).ToString(),
                        Spalte49 = random.Next(100, 10000).ToString(),
                        Spalte50 = random.Next(100, 10000).ToString()
    
                    });
                }
            }
        }
    }
    

    using DocumentFormat.OpenXml;
    using DocumentFormat.OpenXml.Packaging;
    using DocumentFormat.OpenXml.Spreadsheet;
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    
    namespace OpenXMLSample
    {
        public class Report
        {
            public void CreateExcelDoc(string fileName)
            {
                using (SpreadsheetDocument document = SpreadsheetDocument.Create(fileName, SpreadsheetDocumentType.Workbook))
                {
                    WorkbookPart workbookPart = document.AddWorkbookPart();
                    workbookPart.Workbook = new Workbook();
    
                    WorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
                    worksheetPart.Worksheet = new Worksheet();
    
                    Sheets sheets = workbookPart.Workbook.AppendChild(new Sheets());
    
                    Sheet sheet = new Sheet() { Id = workbookPart.GetIdOfPart(worksheetPart), SheetId = 1, Name = "Employees" };
    
                    sheets.Append(sheet);
    
                    workbookPart.Workbook.Save();
    
                    List<Employee> employees = Employees.EmployeesList;
    
                    SheetData sheetData = worksheetPart.Worksheet.AppendChild(new SheetData());
    
                    // Constructing header
                    Row row = new Row();
    
                    row.Append(
                        ConstructCell("Id", CellValues.String),
                        ConstructCell("Name", CellValues.String),
                        ConstructCell("Birth Date", CellValues.String),
                        ConstructCell("Salary", CellValues.String),
                        ConstructCell("Spalte 05", CellValues.String),
                        ConstructCell("Spalte 06", CellValues.String),
                        ConstructCell("Spalte 07", CellValues.String),
                        ConstructCell("Spalte 08", CellValues.String),
                        ConstructCell("Spalte 09", CellValues.String),
                        ConstructCell("Spalte 10", CellValues.String),
                        ConstructCell("Spalte 11", CellValues.String),
                        ConstructCell("Spalte 12", CellValues.String),
                        ConstructCell("Spalte 13", CellValues.String),
                        ConstructCell("Spalte 14", CellValues.String),
                        ConstructCell("Spalte 15", CellValues.String),
                        ConstructCell("Spalte 16", CellValues.String),
                        ConstructCell("Spalte 17", CellValues.String),
                        ConstructCell("Spalte 18", CellValues.String),
                        ConstructCell("Spalte 19", CellValues.String),
                        ConstructCell("Spalte 20", CellValues.String),
                        ConstructCell("Spalte 21", CellValues.String),
                        ConstructCell("Spalte 22", CellValues.String),
                        ConstructCell("Spalte 23", CellValues.String),
                        ConstructCell("Spalte 24", CellValues.String),
                        ConstructCell("Spalte 25", CellValues.String),
                        ConstructCell("Spalte 26", CellValues.String),
                        ConstructCell("Spalte 27", CellValues.String),
                        ConstructCell("Spalte 28", CellValues.String),
                        ConstructCell("Spalte 29", CellValues.String),
                        ConstructCell("Spalte 30", CellValues.String),
                        ConstructCell("Spalte 31", CellValues.String),
                        ConstructCell("Spalte 32", CellValues.String),
                        ConstructCell("Spalte 33", CellValues.String),
                        ConstructCell("Spalte 34", CellValues.String),
                        ConstructCell("Spalte 35", CellValues.String),
                        ConstructCell("Spalte 36", CellValues.String),
                        ConstructCell("Spalte 37", CellValues.String),
                        ConstructCell("Spalte 38", CellValues.String),
                        ConstructCell("Spalte 39", CellValues.String),
                        ConstructCell("Spalte 40", CellValues.String),
                        ConstructCell("Spalte 41", CellValues.String),
                        ConstructCell("Spalte 42", CellValues.String),
                        ConstructCell("Spalte 43", CellValues.String),
                        ConstructCell("Spalte 44", CellValues.String),
                        ConstructCell("Spalte 45", CellValues.String),
                        ConstructCell("Spalte 46", CellValues.String),
                        ConstructCell("Spalte 47", CellValues.String),
                        ConstructCell("Spalte 48", CellValues.String),
                        ConstructCell("Spalte 49", CellValues.String),
                        ConstructCell("Spalte 50", CellValues.String)
                        
                        
                        );
    
                    // Insert the header row to the Sheet Data
                    sheetData.AppendChild(row);
    
                    Stopwatch sw = new Stopwatch();
                    sw.Start();
    
                    // Inserting each employee
                    foreach (var employee in employees)
                    {
                        row = new Row();
    
                        row.Append(
                            ConstructCell(employee.Id.ToString(), CellValues.Number),
                            ConstructCell(employee.Name, CellValues.String),
                            ConstructCell(employee.DOB.ToString("yyyy/MM/dd"), CellValues.String),
                            ConstructCell(employee.Salary.ToString(), CellValues.Number),
                            ConstructCell(employee.Spalte05, CellValues.String),
                            ConstructCell(employee.Spalte06, CellValues.String),
                            ConstructCell(employee.Spalte07, CellValues.String),
                            ConstructCell(employee.Spalte08, CellValues.String),
                            ConstructCell(employee.Spalte09, CellValues.String),
                            ConstructCell(employee.Spalte10, CellValues.String),
                            ConstructCell(employee.Spalte11, CellValues.String),
                            ConstructCell(employee.Spalte12, CellValues.String),
                            ConstructCell(employee.Spalte13, CellValues.String),
                            ConstructCell(employee.Spalte14, CellValues.String),
                            ConstructCell(employee.Spalte15, CellValues.String),
                            ConstructCell(employee.Spalte16, CellValues.String),
                            ConstructCell(employee.Spalte17, CellValues.String),
                            ConstructCell(employee.Spalte18, CellValues.String),
                            ConstructCell(employee.Spalte19, CellValues.String),
                            ConstructCell(employee.Spalte20, CellValues.String),
                            ConstructCell(employee.Spalte21, CellValues.String),
                            ConstructCell(employee.Spalte22, CellValues.String),
                            ConstructCell(employee.Spalte23, CellValues.String),
                            ConstructCell(employee.Spalte24, CellValues.String),
                            ConstructCell(employee.Spalte25, CellValues.String),
                            ConstructCell(employee.Spalte26, CellValues.String),
                            ConstructCell(employee.Spalte27, CellValues.String),
                            ConstructCell(employee.Spalte28, CellValues.String),
                            ConstructCell(employee.Spalte29, CellValues.String),
                            ConstructCell(employee.Spalte30, CellValues.String),
                            ConstructCell(employee.Spalte31, CellValues.String),
                            ConstructCell(employee.Spalte32, CellValues.String),
                            ConstructCell(employee.Spalte33, CellValues.String),
                            ConstructCell(employee.Spalte34, CellValues.String),
                            ConstructCell(employee.Spalte35, CellValues.String),
                            ConstructCell(employee.Spalte36, CellValues.String),
                            ConstructCell(employee.Spalte37, CellValues.String),
                            ConstructCell(employee.Spalte38, CellValues.String),
                            ConstructCell(employee.Spalte39, CellValues.String),
                            ConstructCell(employee.Spalte40, CellValues.String),
                            ConstructCell(employee.Spalte41, CellValues.String),
                            ConstructCell(employee.Spalte42, CellValues.String),
                            ConstructCell(employee.Spalte43, CellValues.String),
                            ConstructCell(employee.Spalte44, CellValues.String),
                            ConstructCell(employee.Spalte45, CellValues.String),
                            ConstructCell(employee.Spalte46, CellValues.String),
                            ConstructCell(employee.Spalte47, CellValues.String),
                            ConstructCell(employee.Spalte48, CellValues.String),
                            ConstructCell(employee.Spalte49, CellValues.String),
                            ConstructCell(employee.Spalte50, CellValues.String)
                            );
    
                        sheetData.AppendChild(row);
                    }
                    worksheetPart.Worksheet.Save();
                    sw.Stop();
                    Console.WriteLine($"Export (1)-Dauer {sw.ElapsedMilliseconds} ms");
    
                    
                }
            }
    
            private Cell ConstructCell(string value, CellValues dataType)
            {
                return new Cell()
                {
                    CellValue = new CellValue(value),
                    DataType = new EnumValue<CellValues>(dataType)
                };
            }
            
        }
    }
    

    Gruß


    Freiberufler im Bereich Softwareentwicklung Von der PLC und Robotik zu VB.NET & C#, vorrangig WPF und UWP

    Mittwoch, 28. November 2018 08:25
  • Hi Stefan,
    und welche Zeiten werden mit Deiner Demo erreicht?

    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP für Developer Technologies)
    Meine Homepage mit Tipps und Tricks

    Mittwoch, 28. November 2018 08:43
  • Hallo Peter,

    debug: 1570ms

    release: 931ms

    Das ist aber wahrscheinlich auch pc-abhängig. Ich wollte schnell eine Demo zum Vergleich aus den Demos von euch und meiner erstellen, bekomme aber folgenden Fehler (bei dem Code von Stefan Falz):

    System.Data.OleDb.OleDbException: "The INSERT INTO statement contains the following unknown field name: 'ID'. Make sure you have typed the name correctly, and try the operation again."

    ...dauert also noch ein bisschen :)

    Zum Vergleich, deine Demo (Module Module45) läuft hier mit:

    debug: 4500ms

    release: 4340ms

    relativ gleich lang...

    Gruß


    Freiberufler im Bereich Softwareentwicklung Von der PLC und Robotik zu VB.NET & C#, vorrangig WPF und UWP


    Mittwoch, 28. November 2018 09:10
  • Hallo Stefan,

    die Spalten müssen in der Exceldatei in der Tabelle1 vorhandein sein. Das hatte ich jetzt nicht im Code gemacht.

    Die Exceldatei findest du hier.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
    https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, Remotesupport

    Mittwoch, 28. November 2018 09:20
    Moderator
  • Hallo Stefan,

    war klar, das ich etwas vergessen habe... Danke!

    Ich habe jetzt mal auf die schnelle (2 Durchläufe) die Demos getestet:

    OpenXml:

    debug= 1570ms

    release= 930ms

    Modul45 (Peter):

    debug= 4500ms

    release= 4340ms

    WriteExcel (Stefan Falz):

    debug= 4010ms

    release= 3700ms

    WriteExcel2 (Stefan Falz):

    debug= 4810ms

    release= 4400ms

    Gruß


    Freiberufler im Bereich Softwareentwicklung Von der PLC und Robotik zu VB.NET & C#, vorrangig WPF und UWP

    Mittwoch, 28. November 2018 09:37
  • Hi,
    wer es wirklich schnell haben will und nur Daten (ohne Formatierung) auszugeben hat, ist mit csv noch viel schneller, bei mir 59 ms.

    Imports System.IO
    
    Module Module42
      Sub Main()
        Try
          Dim c As New Demo
          c.Execute()
        Catch ex As Exception
          Console.WriteLine(ex.Message)
        End Try
        Console.WriteLine("weiter mit Taste")
        Console.ReadKey()
      End Sub
    
      Friend Class Demo
        Private fileName As String = "c:\temp\x.csv"
    
        Friend Sub Execute()
          Dim sw As New Stopwatch
          sw.Start()
          Using wrt As New StreamWriter(fileName)
            For i = 1 To 1000
              For k = 1 To 50
                wrt.Write($"Zelle {i} {k}")
              Next
              wrt.WriteLine()
            Next
          End Using
          sw.Stop()
          Console.WriteLine($"Export-Dauer {sw.ElapsedMilliseconds} ms")
        End Sub
    
      End Class
    
    End Module



    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP für Developer Technologies)
    Meine Homepage mit Tipps und Tricks

    Mittwoch, 28. November 2018 10:50