Как я могу написать в электронную таблицу Excel, используя Linq? - PullRequest
10 голосов
/ 07 октября 2009

Я пишу приложение, в котором мне нужно извлечь некоторые строки из БД и выгрузить их в электронную таблицу Excel. Я использую Linq для получения этих строк.

Можно ли вывести эти строки непосредственно в их аналоги на листе Excel (где одна ячейка в Excel соответствует одной ячейке из БД)?

Ответы [ 6 ]

18 голосов
/ 09 октября 2009

Я лично не большой поклонник использования библиотек для таких вещей, как я всегда нахожу это ограничивающим в какой-то момент позже ...

Я использовал отражение, чтобы сгенерировать заголовки столбцов и получить значения ячеек для каждой строки. А если вы используете .NET Framework 3.5, вы можете использовать методы расширений, чтобы вы могли экспортировать любой IEnumerable<object> в файл Excel XDocument.

Вот как я это сделал:

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;
        }
    }
}

Я также создал еще один метод расширения для облегчения возврата XDocument в веб-сценариях:

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;
}

Надеюсь, это поможет!

5 голосов
/ 07 октября 2009

Нет прямого способа соединить эти два. Похоже, вы хотите, чтобы LINQ to SQL обрабатывал генерацию запросов, но не отображение O / R (потому что Excel не знал, что делать с объектами, выходящими из LINQ - они больше не выглядят как строки данных ). Вы можете выполнить эту первую часть, вызвав (datacontext) .GetCommand (yourLinqQueryHere), а затем запустив его как CommandText в SqlCommand. Вызовите ExecuteReader (), затем GetSchemaTable (), чтобы выяснить порядок столбцов. Затем (при условии, что вы автоматизируете Excel) передайте результат (DbDataReader) .GetValues ​​() в Excel (рабочий лист) .Row [x] .Values, и он отобразит результаты. Возможно, вам придется изменить порядок. Если вы не автоматизируете Excel, вам нужно выгрузить значения при помощи поставщика Jet OLEDB для Excel с OleDbConnection или использовать сторонний компонент для создания электронной таблицы.

1 голос
/ 07 октября 2009

Взгляните на этого Поставщика объектов данных Excel . Я лично не использовал его функциональность записи, и я адаптировал поддержку чтения для учета порядковых (а также именованных) идентификаторов столбцов, но это может быть шагом в правильном направлении. Имейте в виду, что вы не можете писать или читать из файлов XLSX, если на целевом компьютере не установлен Excel 2003+; Стандартные файлы XLS будут работать на любом компьютере Windows.

Моя адаптированная версия с порядковыми столбцами находится здесь здесь . Вы можете счесть необходимым / полезным реализовать это в текущей версии (по ссылке выше), если вы решите использовать код. Моя версия представляет собой гибрид функций из версии 2.0 и 2.5 - она ​​имеет все функции чтения (с некоторыми обновлениями 2.5), но не записывает. Да, и в отличие от версии 2.0 или 2.5, моя версия не требует, чтобы первый лист в документе Excel назывался «Лист1».

Надеюсь, это поможет!

1 голос
/ 07 октября 2009

Вы можете:

  • Создайте файл CSV, связанный с Excel в большинстве систем.
  • Создайте объект Excel Worksheet и заполните его вручную. Поиск в Google
  • Использование генерирующего элемента управления XLS / XLSX. Я использую Spire.XLS из http://www.e -iceblue.com / xls / xlsintro.htm
0 голосов
/ 07 октября 2009

Тот факт, что вы извлекаете свои данные с помощью LINQ, не имеет значения. Что вам действительно нужно, так это хорошая библиотека для написания Excel. Получив это, вы можете просто перебрать результаты, чтобы создать строки на рабочем листе Excel.

Что касается библиотеки, которую я использовал NPOI , и это было здорово.

0 голосов
/ 07 октября 2009

Самым быстрым решением будет создание CSV-файла:

col1, colb, colc
col1, colb, colc

Excel очень хорошо работает с CSV-файлами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...