2009-10-06 12 views
9

Sto scrivendo un'app in cui ho bisogno di recuperare alcune righe da un DB e di riversarle in un foglio di calcolo Excel. Sto usando Linq per recuperare queste righe.Come posso scrivere su un foglio di calcolo Excel usando Linq?

È possibile scaricare queste righe direttamente nelle loro controparti nel foglio di Excel (dove una cella in Excel corrisponde a una cella del DB)?

risposta

5

Non esiste un modo diretto per collegare questi due. Sembra che tu voglia LINQ su SQL per gestire la generazione di query, ma non il mapping O/R (perché Excel non saprebbe cosa fare con gli oggetti che escono da LINQ - non sembrano più righe di dati). È possibile eseguire la prima parte chiamando (datacontext) .GetCommand (yourLinqQueryHere), quindi eseguendolo come CommandText in SqlCommand. Chiama ExecuteReader(), quindi GetSchemaTable() per calcolare l'ordine delle colonne. Quindi, supponendo che tu stia automatizzando Excel, passa il risultato di (DbDataReader) .GetValues ​​() a Excel (foglio di lavoro) .Row [x] .Values ​​e dividerà i risultati. Potrebbe essere necessario riordinare le cose. Se non si automatizza Excel, è necessario eseguire il dump dei valori utilizzando il provider OLEDB Jet per Excel con un OleDbConnection oppure utilizzare un componente di terze parti per generare il foglio di calcolo.

0

la soluzione più rapida sarà quella di creare un file CSV:

col1, colb, colc 
col1, colb, colc 

Excel funziona molto bene con i file CSV.

1

Dai un'occhiata a questo Excel Data Object Provider. Non ho usato personalmente la funzionalità di scrittura di esso e ho adattato il supporto di lettura per consentire identificatori di colonna ordinali (così come denominati), ma potrebbe essere un passo nella giusta direzione. Tenere presente che non è possibile scrivere o leggere dai file XLSX a meno che Excel 2003+ sia installato sul computer di destinazione; i file XLS standard funzioneranno comunque su qualsiasi box di Windows.

La mia versione adattata con colonne ordinali può essere trovata here. Potresti trovare necessario/utile implementarlo nella versione corrente (al link sopra) se decidi di utilizzare il codice. La mia versione è un ibrido di funzionalità dal version 2.0 e 2.5- ha tutte le funzionalità di lettura (con alcuni aggiornamenti 2.5), ma nessuna scrittura. A differenza della versione 2.0 o 2.5, la mia versione non richiede che il primo foglio del documento Excel sia denominato "Foglio1".

Spero che questo aiuti!

0

Il fatto che stai recuperando i tuoi dati con LINQ è un po 'irrilevante. Quello che stai cercando è una buona libreria per scrivere Excel. Una volta ottenuto ciò, puoi semplicemente scorrere i risultati per creare righe nel foglio di lavoro Excel.

Per quanto riguarda una libreria, ho usato NPOI ed è stato fantastico.

17

Personalmente non sono un grande fan dell'uso delle librerie per cose come le trovo sempre limitanti a un certo punto ...

Ho usato la riflessione per generare le intestazioni di colonna e ottenere i valori di cella di ogni riga. E se si utilizza .NET Framework 3.5, è possibile sfruttare i metodi di estensioni in modo da poter esportare qualsiasi IEnumerable<object> in un file XDocument excel.

Ecco come ho fatto:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Xml.Linq; 

namespace YourNameSpace 
{ 
    public static class ExcelExportExtensions 
    { 
     public static XDocument ToExcelXml(this IEnumerable<object> rows) 
     { 
      return rows.ToExcelXml("Sheet1"); 
     } 

     public static XDocument ToExcelXml(this IEnumerable<object> rows, string sheetName) 
     { 
      sheetName = sheetName.Replace("/", "-"); 
      sheetName = sheetName.Replace("\\", "-"); 

      XNamespace mainNamespace = "urn:schemas-microsoft-com:office:spreadsheet"; 
      XNamespace o = "urn:schemas-microsoft-com:office:office"; 
      XNamespace x = "urn:schemas-microsoft-com:office:excel"; 
      XNamespace ss = "urn:schemas-microsoft-com:office:spreadsheet"; 
      XNamespace html = "http://www.w3.org/TR/REC-html40"; 

      XDocument xdoc = new XDocument(new XDeclaration("1.0", "utf-8", "yes")); 

      var headerRow = from p in rows.First().GetType().GetProperties() 
          select new XElement(mainNamespace + "Cell", 
           new XElement(mainNamespace + "Data", 
            new XAttribute(ss + "Type", "String"), p.Name)); //Generate header using reflection 

      XElement workbook = new XElement(mainNamespace + "Workbook", 
       new XAttribute(XNamespace.Xmlns + "html", html), 
       new XAttribute(XName.Get("ss", "http://www.w3.org/2000/xmlns/"), ss), 
       new XAttribute(XName.Get("o", "http://www.w3.org/2000/xmlns/"), o), 
       new XAttribute(XName.Get("x", "http://www.w3.org/2000/xmlns/"), x), 
       new XAttribute(XName.Get("xmlns", ""), mainNamespace), 
       new XElement(o + "DocumentProperties", 
         new XAttribute(XName.Get("xmlns", ""), o), 
         new XElement(o + "Author", "Smartdesk Systems Ltd"), 
         new XElement(o + "LastAuthor", "Smartdesk Systems Ltd"), 
         new XElement(o + "Created", DateTime.Now.ToString()) 
        ), //end document properties 
       new XElement(x + "ExcelWorkbook", 
         new XAttribute(XName.Get("xmlns", ""), x), 
         new XElement(x + "WindowHeight", 12750), 
         new XElement(x + "WindowWidth", 24855), 
         new XElement(x + "WindowTopX", 240), 
         new XElement(x + "WindowTopY", 75), 
         new XElement(x + "ProtectStructure", "False"), 
         new XElement(x + "ProtectWindows", "False") 
        ), //end ExcelWorkbook 
       new XElement(mainNamespace + "Styles", 
         new XElement(mainNamespace + "Style", 
          new XAttribute(ss + "ID", "Default"), 
          new XAttribute(ss + "Name", "Normal"), 
          new XElement(mainNamespace + "Alignment", 
           new XAttribute(ss + "Vertical", "Bottom") 
          ), 
          new XElement(mainNamespace + "Borders"), 
          new XElement(mainNamespace + "Font", 
           new XAttribute(ss + "FontName", "Calibri"), 
           new XAttribute(x + "Family", "Swiss"), 
           new XAttribute(ss + "Size", "11"), 
           new XAttribute(ss + "Color", "#000000") 
          ), 
          new XElement(mainNamespace + "Interior"), 
          new XElement(mainNamespace + "NumberFormat"), 
          new XElement(mainNamespace + "Protection") 
         ), 
         new XElement(mainNamespace + "Style", 
          new XAttribute(ss + "ID", "Header"), 
          new XElement(mainNamespace + "Font", 
           new XAttribute(ss + "FontName", "Calibri"), 
           new XAttribute(x + "Family", "Swiss"), 
           new XAttribute(ss + "Size", "11"), 
           new XAttribute(ss + "Color", "#000000"), 
           new XAttribute(ss + "Bold", "1") 
          ) 
         ) 
        ), // close styles 
        new XElement(mainNamespace + "Worksheet", 
         new XAttribute(ss + "Name", sheetName /* Sheet name */), 
         new XElement(mainNamespace + "Table", 
          new XAttribute(ss + "ExpandedColumnCount", headerRow.Count()), 
          new XAttribute(ss + "ExpandedRowCount", rows.Count() + 1), 
          new XAttribute(x + "FullColumns", 1), 
          new XAttribute(x + "FullRows", 1), 
          new XAttribute(ss + "DefaultRowHeight", 15), 
          new XElement(mainNamespace + "Column", 
           new XAttribute(ss + "Width", 81) 
          ), 
          new XElement(mainNamespace + "Row", new XAttribute(ss + "StyleID", "Header"), headerRow), 
          from contentRow in rows 
          select new XElement(mainNamespace + "Row", 
           new XAttribute(ss + "StyleID", "Default"), 
            from p in contentRow.GetType().GetProperties() 
            select new XElement(mainNamespace + "Cell", 
             new XElement(mainNamespace + "Data", new XAttribute(ss + "Type", "String"), p.GetValue(contentRow, null))) /* Build cells using reflection */) 
         ), //close table 
         new XElement(x + "WorksheetOptions", 
          new XAttribute(XName.Get("xmlns", ""), x), 
          new XElement(x + "PageSetup", 
           new XElement(x + "Header", 
            new XAttribute(x + "Margin", "0.3") 
           ), 
           new XElement(x + "Footer", 
            new XAttribute(x + "Margin", "0.3") 
           ), 
           new XElement(x + "PageMargins", 
            new XAttribute(x + "Bottom", "0.75"), 
            new XAttribute(x + "Left", "0.7"), 
            new XAttribute(x + "Right", "0.7"), 
            new XAttribute(x + "Top", "0.75") 
           ) 
          ), 
          new XElement(x + "Print", 
           new XElement(x + "ValidPrinterInfo"), 
           new XElement(x + "HorizontalResolution", 600), 
           new XElement(x + "VerticalResolution", 600) 
          ), 
          new XElement(x + "Selected"), 
          new XElement(x + "Panes", 
           new XElement(x + "Pane", 
            new XElement(x + "Number", 3), 
            new XElement(x + "ActiveRow", 1), 
            new XElement(x + "ActiveCol", 0) 
           ) 
          ), 
          new XElement(x + "ProtectObjects", "False"), 
          new XElement(x + "ProtectScenarios", "False") 
         ) // close worksheet options 
        ) // close Worksheet 
       ); 

      xdoc.Add(workbook); 

      return xdoc; 
     } 
    } 
} 

ho creato anche un altro metodo di estensione per facilitare restituire il XDocument in scenari web:

public static DownloadableFile ToDownloadableXmlFileForExcel2003(this System.Xml.Linq.XDocument file, string fileName) 
{ 
    MemoryStream ms = new MemoryStream(); 

    XmlWriterSettings xmlWriterSettings = new XmlWriterSettings() { Encoding = Encoding.UTF8 }; 
    XmlWriter xmlWriter = XmlWriter.Create(ms, xmlWriterSettings); 

    file.Save(xmlWriter); //.Save() adds the <xml /> header tag! 
    xmlWriter.Close();  //Must close the writer to dump it's content its output (the memory stream) 

    DownloadableFile dbf = 
      new DownloadableFile 
      { 
       FileName = String.Format("{0}.xls", fileName.Replace(" ", "")), 
       Content = ms.ToArray(), 
       MimeType = "application/vnd.ms-excel" 
      }; 

    ms.Close(); 
    ms.Dispose(); 

    return dbf; 
} 

Spero che questo aiuti!

+1

Ho aggiornato il metodo di estensione ToDownloadableXmlFileForExcel2003() per utilizzare un oggetto MemoryStream invece di .ToString() che causa eccezioni OutOfMemoryException. Un problema con il mio modo di generare documenti XML XLS è la dimensione dei file. Va bene per i documenti piccoli, ma non per i grandi fogli xls con linee di 100k +. – bounav

+2

Sembra interessante, ma l'ho provato, ma viene visualizzato un messaggio d'errore "Excel non può aprire il file 'newexcelfil2.xlsx' perché il formato del file o l'estensione del file non è valido. Verificare che il file non sia danneggiato e che l'estensione del file corrisponda al formato del file. " Ho verificato che l'xml è ben formato. – tjp69

1

Scrivi Excel XML con LINQ to XML

è incredibilmente semplice, non richiede librerie esterne, e utilizza la riflessione di trasformare qualsiasi IEnumerable in un foglio di lavoro!

http://scottstjohn.wordpress.com/2011/04/02/write-to-excel-xml-with-linq-to-xml/

Come descritto dall'autore, Scott S. Giovanni (sto cercando di indovinare questo dal suo URL - non ha alcuna informazione bio sul suo sito):

ho trovato una vera e propria classe di estensione per scrivere qualsiasi oggetto IEnumerable in un foglio di calcolo XML di Excel . Vedi C# scrivi su Excel usando Linq con bounav. I ha apportato un paio di modifiche perché desiderava poter aggiungere nuovi IErumerabili come fogli di lavoro. Vedere un esempio e il codice sorgente sotto

Ho praticamente copiato/incollato il suo codice in MyExtensions in LINQPad e l'ho usato subito.

Problemi correlati