2009-10-06 24 views
9

Tôi đang viết một ứng dụng mà tôi cần truy xuất một số hàng từ một DB và đổ chúng vào một bảng tính Excel. Tôi đang sử dụng LINQ để lấy những hàng này.Làm cách nào để ghi vào bảng tính Excel bằng LINQ?

Có thể đưa các hàng này trực tiếp vào các đối tác của chúng trong bảng Excel (trong đó một ô trong Excel tương ứng với một ô từ DB) không?

Trả lời

5

Không có cách nào trực tiếp để kết nối cả hai. Có vẻ như bạn muốn LINQ to SQL xử lý việc tạo truy vấn, nhưng không phải là ánh xạ O/R (vì Excel sẽ không biết phải làm gì với các đối tượng đi ra khỏi LINQ- chúng không giống các hàng dữ liệu nữa). Bạn có thể thực hiện phần đầu tiên bằng cách gọi (datacontext) .GetCommand (yourLinqQueryHere), sau đó chạy nó như là CommandText trong một SqlCommand. Gọi ExecuteReader(), sau đó GetSchemaTable() để tìm ra thứ tự của các cột. Sau đó (giả sử bạn đang tự động hóa Excel) chuyển kết quả của (DbDataReader) .GetValues ​​() tới Excel (Worksheet) .Row [x] .Values ​​và nó sẽ chia kết quả. Bạn có thể cần phải sắp xếp lại thứ. Nếu bạn không tự động hóa Excel, bạn cần phải đổ giá trị bằng cách sử dụng nhà cung cấp máy bay phản lực OLEDB cho Excel với một OleDbConnection hoặc sử dụng thành phần bên thứ 3 để tạo bảng tính.

0

Giải pháp nhanh nhất sẽ được để tạo ra một tập tin csv:

col1, colb, colc 
col1, colb, colc 

Excel hoạt động rất tốt với các tập tin csv.

1

Bạn có thể:

  • Tạo một file CSV, đó là liên kết với Excel trên hầu hết các hệ thống.
  • Tạo đối tượng Trang tính Excel và điền nó theo cách thủ công. Google Search
  • Sử dụng điều khiển tạo XLS/XLSX. Tôi đã sử dụng Spire.XLS từ http://www.e-iceblue.com/xls/xlsintro.htm
1

Hãy xem Excel Data Object Provider này. Tôi chưa đích thân sử dụng chức năng viết của nó và tôi đã điều chỉnh hỗ trợ đọc để cho phép nhận dạng cột thứ tự (cũng như được đặt tên), nhưng nó có thể là một bước đi đúng hướng. Hãy nhớ rằng bạn không thể viết hoặc đọc từ các tệp XLSX trừ khi Excel 2003+ được cài đặt trên máy đích; các tệp XLS chuẩn sẽ hoạt động trên bất kỳ hộp Windows nào.

Phiên bản được điều chỉnh của tôi với các cột thứ tự có thể được tìm thấy here. Bạn có thể thấy cần thiết/hữu ích để thực hiện điều đó trong phiên bản hiện tại (tại liên kết ở trên) nếu bạn quyết định sử dụng mã. Phiên bản của tôi là sự kết hợp các tính năng từ version 2.0 và 2.5- nó có tất cả chức năng đọc (với khoảng 2.5 nâng cấp), nhưng không có văn bản. Oh- và không giống như phiên bản 2.0 hoặc 2.5, phiên bản của tôi không yêu cầu trang tính đầu tiên trong tài liệu Excel được đặt tên là "Sheet1".

Hy vọng điều đó sẽ hữu ích!

0

Thực tế là bạn đang truy xuất dữ liệu của mình với LINQ là loại không liên quan. Những gì bạn đang thực sự sau là một thư viện tốt để viết Excel. Một khi bạn đã có điều đó, bạn chỉ có thể lặp qua các kết quả của bạn để tạo các hàng trong bảng tính Excel của bạn.

Theo như thư viện tôi đã sử dụng NPOI và thật tuyệt vời.

17

Cá nhân tôi không phải là người hâm mộ lớn sử dụng thư viện cho những thứ như vậy vì tôi luôn thấy nó hạn chế ở một số thời điểm sau đó ...

Tôi đã sử dụng phản chiếu để tạo tiêu đề cột và nhận giá trị ô của mỗi hàng. Và nếu bạn đang sử dụng .NET framework 3.5, bạn có thể tận dụng các phương pháp mở rộng để bạn có thể xuất bất kỳ IEnumerable<object> thành tệp excel XDocument nào.

Sau đây là cách tôi đã làm nó:

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

Tôi cũng đã tạo ra một phương pháp gia hạn để giảm bớt trả lại XDocument trong kịch bản 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; 
} 

Hope this helps!

+1

Tôi đã cập nhật phương thức mở rộng ToDownloadableXmlFileForExcel2003() để sử dụng đối tượng MemoryStream thay vì .ToString() đang gây ra ngoại lệ OutOfMemoryException. Một vấn đề với cách tạo tài liệu XML XLS của tôi là kích thước của các tệp. Nó là tốt cho các tài liệu nhỏ nhưng không cho tờ xls lớn với 100k + dòng trong đó. – bounav

+2

Điều này có vẻ thú vị nên tôi đã thử nhưng tôi gặp lỗi "Excel không thể mở tệp 'newexcelfil2.xlsx' vì định dạng tệp hoặc mở rộng tệp không hợp lệ. Hãy xác minh rằng tệp chưa bị hỏng và tệp mở rộng khớp với định dạng của tệp. " Tôi đã xác minh rằng xml được định dạng tốt. – tjp69

1

Viết thư cho Excel XML với LINQ to XML

là rất đơn giản, không đòi hỏi các thư viện bên ngoài, và sử dụng phản ánh để biến bất kỳ IEnumerable vào một bảng tính!

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

Như mô tả của tác giả, Scott St. John (Tôi đoán này từ URL của mình - anh ta không có bất kỳ thông tin sinh học trên trang web của mình):

tôi thấy một lớp mở rộng thực sự tốt đẹp để viết bất kỳ IEnumerable vào một bảng tính Excel XML . Xem C# viết cho Excel bằng cách sử dụng LINQ bởi bounav. Tôi thực hiện một vài sửa đổi vì muốn có thể thêm IEnumerables mới làm trang tính. Xem ví dụ và mã nguồn bên dưới

Tôi đã sao chép/dán mã của mình vào MyExtensions trong LINQPad và sử dụng nó ngay lập tức.

Các vấn đề liên quan