jqgrid + EF + MVC:如何在Excel中导出? 你build议哪种方法?

我正在使用jqgrid(标准)与EF 4 + MVC3 。 我想实现Excel导出。 你会build议我哪种方法?

为了生成excel, 我想使用Stephen Walther博士提供的这个库 ,它有三种types的输出,并允许定义头文件。 请告诉我,如果你觉得它对我的目的有效。

我问这个问题,因为我仍然接近实施Excel导出,我发现了几种技术。 有人build议做一个csv导出,其他人则表示应该返回一个JSON输出,而且我不清楚这个function是否存在于jqgrid的免费版本中。 无论如何,我想把这些数据传递给Walther的对象。

关于jqgrid代码,我发现奥列格这个有趣的答案 ,但我不明白是否可以应用于我的需求。

不幸的是,到目前为止,我只findEF MVC的excel导出解决scheme的一部分,但没有解决scheme或完整的例子…

关于MVC逻辑,我将按照@Tommy的build议来实现和开发这个代码 。

如果这个问题可能很愚蠢,那么请抱歉,我只是一个(爱好者)初学者。

感谢您宝贵的帮助! 最好的祝福

正如我以前写的(例如,请参阅这里和这里 ),将网格数据导出为XML的最佳方式是使用Open XML SDK 2.0 。

Stephen Walther博士的post展示了如何创build可以被Excel读取的HTML文件 。 这不是Excel文件,必须仍然转换为Excel格式。 CSV的使用有更多的问题。 根据源表中的内容,自动转换为Excel数据types可能是绝对错误的。 在我为客户开发的一个项目中,电网包含软件产品的信息:产品名称,版本等。 软件版本看起来有些时间(例如1.3.1963),并且这些单元格将被错误地转换(德语中使用“。”作为date中的分隔符)。 结果是一个真正的难题。 带有逗号的文本的CSV的使用也将经常导入错误。 即使一个人引用含有逗号( , )的单元格并且转义了具有配额的文本,导入仍然是错误的,尤其是在第一列中。 我不想在这里解释所有尝试和错误的全部历史,但毕竟我决定放弃使用CSV和HTML,并开始使用Open XML SDK 2.0,它允许创build扩展名为XLSX的真正的Excel文件 。 这种方式看起来很完美,因为不需要在服务器上安装任何Office组件,无需额外的许可证。

唯一的限制是应该能够使用DocumentFormat.OpenXml.dll ,所以你的服务器程序应该在任何Windows操作系统上运行。 众所周知,XLSX文件是ZIP文件,其中包含一些XML文件。 如果您仍然不知道我build议您将XLSX文件重命名为ZIP文件并将其解压缩。 Open XML SDK 2.0是与XML文件一起使用XLSX文件的库。 所以不需要额外的Office组件。

可以find许多关于如何使用Open XML SDK 2.0的信息(请参阅这里和这里 )。 一个凸轮直接在MSDN上find许多有用的代码示例(请参阅此处 )。 尽pipe如此,Open XML SDK 2.0的实际使用至less在第一次并不那么容易。 所以我从我自己使用的代码部分创build了一个演示。

您可以从这里下载演示项目 。 演示是从答案和这个演示的演示的扩展。

要导出数据,我使用DataForExcel助手类。 它具有构造函数的forms

 DataForExcel(string[] headers, DataType[] colunmTypes, List<string[]> data, string sheetName) 

或者以简化的forms

 DataForExcel(string[] headers, List<string[]> data, string sheetName) 

和唯一的公共方法

 CreateXlsxAndFillData(Stream stream) 

类创buildExcel文件的用法可以如下所示

 var excelData = new DataForExcel ( // column Header new[]{"Col1", "Col2", "Col3"}, new[]{DataForExcel.DataType.String, DataForExcel.DataType.Integer, DataForExcel.DataType.String}, new List<string[]> { new[] {"a", "1", "c1"}, new[] {"a", "2", "c2"} }, "Test Grid"); Stream stream = new FileStream ("Test.xlsx", FileMode.Create); excelData.CreateXlsxAndFillData (stream); stream.Close(); 

在ASP.NET MVC演示中的用法如下

 static readonly string[] HeadersQuestions = { "Id", "Votes", "Title" }; static readonly DataForExcel.DataType[] ColunmTypesQuestions = { DataForExcel.DataType.Integer, DataForExcel.DataType.Integer, DataForExcel.DataType.String }; public ActionResult ExportAllQuestionsToExcel () { var context = new HaackOverflowEntities (); var questions = context.Questions; questions.MergeOption = MergeOption.NoTracking; // we don't want to update the data // to be able to use ToString() below which is NOT exist in the LINQ to Entity // we should include in query only the properies which we will use below var query = questions.ToList (); if (query.Count == 0) return new EmptyResult (); var data = new List<string[]> (query.Count); data.AddRange (query.Select (item => new[] { item.Id.ToString(CultureInfo.InvariantCulture), item.Votes.ToString(CultureInfo.InvariantCulture), item.Title })); return new ExcelResult (HeadersQuestions, ColunmTypesQuestions, data, "Questions.xlsx", "Questions"); } 

ExcelResult被定义为

 public class ExcelResult : ActionResult { private readonly DataForExcel _data; private readonly string _fileName; public ExcelResult (string[] headers, List<string[]> data, string fileName, string sheetName) { _data = new DataForExcel (headers, data, sheetName); _fileName = fileName; } public ExcelResult (string[] headers, DataForExcel.DataType[] colunmTypes, List<string[]> data, string fileName, string sheetName) { _data = new DataForExcel (headers, colunmTypes, data, sheetName); _fileName = fileName; } public override void ExecuteResult (ControllerContext context) { var response = context.HttpContext.Response; response.ClearContent(); response.ClearHeaders(); response.Cache.SetMaxAge (new TimeSpan (0)); using (var stream = new MemoryStream()) { _data.CreateXlsxAndFillData (stream); //Return it to the client - strFile has been updated, so return it. response.AddHeader ("content-disposition", "attachment; filename=" + _fileName); // see http://filext.com/faq/office_mime_types.php response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; response.ContentEncoding = Encoding.UTF8; stream.WriteTo (response.OutputStream); } response.Flush(); response.Close(); } } 

为了使代码充分,我必须包括类DataForExcel的代码:

 public class DataForExcel { public enum DataType { String, Integer } private readonly string[] _headers; private readonly DataType[] _colunmTypes; private readonly List<string[]> _data; private readonly string _sheetName = "Grid1"; private readonly SortedSet<string> _os = new SortedSet<string> (); private string[] _sharedStrings; private static string ConvertIntToColumnHeader(int index) { var sb = new StringBuilder (); while (index > 0) { if (index <= 'Z' - 'A') // index=0 -> 'A', 25 -> 'Z' break; sb.Append (ConvertIntToColumnHeader (index / ('Z' - 'A' + 1) - 1)); index = index % ('Z' - 'A' + 1); } sb.Append ((char)('A' + index)); return sb.ToString (); } private static Row CreateRow(UInt32 index, IList<string> data) { var r = new Row { RowIndex = index }; for (var i = 0; i < data.Count; i++) r.Append (new OpenXmlElement[] { CreateTextCell (ConvertIntToColumnHeader (i), index, data[i]) }); return r; } private Row CreateRowWithSharedStrings(UInt32 index, IList<string> data) { var r = new Row { RowIndex = index }; for (var i = 0; i < data.Count; i++) r.Append (new OpenXmlElement[] { CreateSharedTextCell (ConvertIntToColumnHeader (i), index, data[i]) }); return r; } private Row CreateRowWithSharedStrings(UInt32 index, IList<string> data, IList<DataType> colunmTypes) { var r = new Row { RowIndex = index }; for (var i = 0; i < data.Count; i++) if (colunmTypes != null && i < colunmTypes.Count && colunmTypes[i] == DataType.Integer) r.Append (new OpenXmlElement[] { CreateNumberCell (ConvertIntToColumnHeader (i), index, data[i]) }); else r.Append (new OpenXmlElement[] { CreateSharedTextCell (ConvertIntToColumnHeader (i), index, data[i]) }); return r; } private static Cell CreateTextCell(string header, UInt32 index, string text) { // create Cell with InlineString as a child, which has Text as a child return new Cell (new InlineString (new Text { Text = text })) { // Cell properties DataType = CellValues.InlineString, CellReference = header + index }; } private Cell CreateSharedTextCell(string header, UInt32 index, string text) { for (var i=0; i<_sharedStrings.Length; i++) { if (String.Compare (_sharedStrings[i], text, StringComparison.Ordinal) == 0) { return new Cell (new CellValue { Text = i.ToString (CultureInfo.InvariantCulture) }) { // Cell properties DataType = CellValues.SharedString, CellReference = header + index }; } } // create Cell with InlineString as a child, which has Text as a child throw new InstanceNotFoundException(); } private static Cell CreateNumberCell(string header, UInt32 index, string numberAsString) { // create Cell with CellValue as a child, which has Text as a child return new Cell (new CellValue { Text = numberAsString }) { // Cell properties CellReference = header + index }; } private void FillSharedStringTable(IEnumerable<string> data) { foreach (var item in data) _os.Add (item); } private void FillSharedStringTable(IList<string> data, IList<DataType> colunmTypes) { for (var i = 0; i < data.Count; i++) if (colunmTypes == null || i >= colunmTypes.Count || colunmTypes[i] == DataType.String) _os.Add (data[i]); } public DataForExcel(string[] headers, List<string[]> data, string sheetName) { _headers = headers; _data = data; _sheetName = sheetName; } public DataForExcel(string[] headers, DataType[] colunmTypes, List<string[]> data, string sheetName) { _headers = headers; _colunmTypes = colunmTypes; _data = data; _sheetName = sheetName; } private void FillSpreadsheetDocument(SpreadsheetDocument spreadsheetDocument) { // create and fill SheetData var sheetData = new SheetData (); // first row is the header sheetData.AppendChild (CreateRow (1, _headers)); //const UInt32 iAutoFilter = 2; // skip next row (number 2) for the AutoFilter //var i = iAutoFilter + 1; UInt32 i = 2; // first of all collect all different strings in OrderedSet<string> _os foreach (var dataRow in _data) if (_colunmTypes != null) FillSharedStringTable (dataRow, _colunmTypes); else FillSharedStringTable (dataRow); _sharedStrings = _os.ToArray (); foreach (var dataRow in _data) sheetData.AppendChild (_colunmTypes != null ? CreateRowWithSharedStrings (i++, dataRow, _colunmTypes) : CreateRowWithSharedStrings (i++, dataRow)); var sst = new SharedStringTable (); foreach (var text in _os) sst.AppendChild (new SharedStringItem (new Text (text))); // add empty workbook and worksheet to the SpreadsheetDocument var workbookPart = spreadsheetDocument.AddWorkbookPart (); var worksheetPart = workbookPart.AddNewPart<WorksheetPart> (); var shareStringPart = workbookPart.AddNewPart<SharedStringTablePart> (); shareStringPart.SharedStringTable = sst; shareStringPart.SharedStringTable.Save (); // add sheet data to Worksheet worksheetPart.Worksheet = new Worksheet (sheetData); worksheetPart.Worksheet.Save (); // fill workbook with the Worksheet spreadsheetDocument.WorkbookPart.Workbook = new Workbook ( new FileVersion { ApplicationName = "Microsoft Office Excel" }, new Sheets ( new Sheet { Name = _sheetName, SheetId = (UInt32Value)1U, // generate the id for sheet Id = workbookPart.GetIdOfPart (worksheetPart) } ) ); spreadsheetDocument.WorkbookPart.Workbook.Save (); spreadsheetDocument.Close (); } public void CreateXlsxAndFillData(Stream stream) { // Create workbook document using (var spreadsheetDocument = SpreadsheetDocument.Create (stream, SpreadsheetDocumentType.Workbook)) { FillSpreadsheetDocument (spreadsheetDocument); } } } 

上面的代码直接创build新的XLSX文件。 您可以扩展代码以支持更多的数据types,如我在代码中使用的StringInteger

在更专业的应用程序版本中,您可以创build一些用于导出不同表格的XLSX模板。 在代码中,您可以将数据放置在单元格中,因此请修改电子表格而不是创build。 通过这种方式,您可以创build完美的格式化的XLSX文件。 MSDN的示例(请参阅此处 )将帮助您实现何时需要的方式。

更新 : 答案包含更新的代码,它允许生成更多的单元格格式的Excellogging。

我看着斯蒂芬的post,这是古老的地狱,这顺便说一句,这并不是错的。 如果你不需要自定义格式,标题和样式,那么我认为使用CSV是非常简单的。
更重要的是,不要以为内部使用EF进行数据访问的MVC站点的excel导出比使用ActiveRecord的Ruby on Rails站点更难。 对我来说,这是独立的担忧,出口不应该对底层技术(至less不是直接)有任何新的东西,仅仅是数据的结构,就这些。
search允许进行Excel读取/写入和导出的codeplex库,现在有很多这样的解决scheme,这些解决scheme经常由全球数千名开发人员进行维护和testing。 如果我是你,我不会使用斯蒂芬的解决scheme,因为它看起来像他偶尔键入一个记事本,然后粘贴到后 – 没有unit testing,没有扩展性+它在VB中,所以它更难以理解,但可能是这只是我。 希望这个帮助,祝你好运