【问题标题】:How can I write to an Excel spreadsheet using Linq?如何使用 Linq 写入 Excel 电子表格?
【发布时间】:2009-10-06 20:03:44
【问题描述】:

我正在编写一个应用程序,我需要从数据库中检索一些行并将它们转储到 Excel 电子表格中。我正在使用 Linq 来检索这些行。

是否可以将这些行直接转储到 Excel 工作表中的对应行(Excel 中的一个单元格对应数据库中的一个单元格)?

【问题讨论】:

    标签: c# linq excel interop


    【解决方案1】:

    我个人不太喜欢使用库来处理这样的事情,因为我以后总是发现它在某些时候会受到限制......

    我使用反射来生成列标题并获取每行的单元格值。如果您使用的是 .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;
            }
        }
    }
    

    我还创建了另一种扩展方法来轻松返回 Web 场景中的 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;
    }
    

    希望这会有所帮助!

    【讨论】:

    • 我已更新 ToDownloadableXmlFileForExcel2003() 扩展方法以使用 MemoryStream 对象而不是导致 OutOfMemoryException 异常的 .ToString()。我生成 XML XLS 文档的方式的一个问题是文件的大小。它适用于小型文档,但不适用于其中包含 100k+ 行的大型 xls 表。
    • 这看起来很酷,所以我试了一下,但出现错误“Excel 无法打开文件‘newexcelfil2.xlsx’,因为文件格式或文件扩展名无效。验证文件没有损坏并且文件扩展名与文件的格式匹配。”我已经验证了 xml 格式正确。
    • 有人找到了您的代码并进行了少量修改,并添加了一个方法 ToExcelXmlWorksheet()。他们的代码在scottstjohn.wordpress.com/2011/04/02/…
    【解决方案2】:

    没有直接的方法可以将这两者联系起来。听起来您希望 LINQ to SQL 处理查询生成,而不是 O/R 映射(因为 Excel 不知道如何处理来自 LINQ 的对象 - 它们看起来不再像数据行)。您可以通过调用 (datacontext).GetCommand(yourLinqQueryHere) 来完成第一部分,然后将其作为 SqlCommand 中的 CommandText 运行。调用 ExecuteReader(),然后调用 GetSchemaTable() 来确定列的顺序。然后(假设您正在使 Excel 自动化)将 (DbDataReader).GetValues() 的结果传递给 Excel 的 (Worksheet).Row[x].Values,它会将结果放入其中。您可能需要重新排序。如果您不自动化 Excel,则需要在使用带有 OleDbConnection 的 Excel 的 Jet OLEDB 提供程序时转储值,或使用第 3 方组件来生成电子表格。

    【讨论】:

      【解决方案3】:

      你可以:

      【讨论】:

        【解决方案4】:

        看看这个Excel Data Object Provider。我没有亲自使用它的写入功能,并且我调整了读取支持以允许序数(以及命名)列标识符,但这可能是朝着正确方向迈出的一步。请记住,除非在目标计算机上安装了 Excel 2003+,否则您无法写入或读取 XLSX 文件;标准的 XLS 文件可以在任何 Windows 机器上运行。

        可以在here 找到我的带有序数列的改编版本。如果您决定使用代码,您可能会发现在当前版本(在上面的链接)中实现它是必要的/有帮助的。我的版本是version 2.0 和 2.5 的混合功能——它具有所有的阅读功能(有一些 2.5 升级),但没有写作。哦 - 与 2.0 或 2.5 版本不同,我的版本不要求 Excel 文档中的第一个工作表命名为“Sheet1”。

        希望有帮助!

        【讨论】:

          【解决方案5】:

          最快的解决方案是创建一个 csv 文件:

          col1, colb, colc
          col1, colb, colc
          

          Excel 可以很好地处理 csv 文件。

          【讨论】:

            【解决方案6】:

            您使用 LINQ 检索数据的事实有点无关紧要。您真正追求的是一个编写 Excel 的好库。完成后,您可以简单地遍历结果以在 Excel 工作表中创建行。

            就我使用过NPOI 的库而言,它非常棒。

            【讨论】:

              猜你喜欢
              • 2017-05-18
              • 2021-12-31
              • 2021-04-05
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-10-17
              • 2016-11-21
              • 2018-12-03
              相关资源
              最近更新 更多