我正在尝试在用户单击按钮时从控制器导出.xlsx文档。我的模型看起来像这样:
public class ExportOrdersViewModel
{
public int Id { get; set; }
public string CustomerFirstName { get; set; }
public string CustomerLastName { get; set; }
public string CustomerEmail { get; set; }
public string CustomerMobile { get; set; }
public string ShippingStreet { get; set; }
public string ShippingCity { get; set; }
public string ShippingCountry { get; set; }
public string ShippingPostalCode { get; set; }
public string ShippingTo { get; set; }
public bool IsShipped { get; set; }
public ICollection<ExportOrdersItemViewModel> Items { get; set; }
}
public class ExportOrdersItemViewModel
{
public string TicketName { get; set; }
public string EventName { get; set; }
public int Quantity { get; set; }
public string CurrencyId { get; set; }
public string PaymentCurrencyId { get; set; }
public string UnitPrice { get; set; }
public string PaymentUnitPrice { get; set; }
}
除了字符串属性,ExportOrdersViewModel还包含一个项目列表。创建文件时,我想在创建行时在单元格中显示此列表。
我正在使用ClosedXML来创建文件。在创建文件之前,在控制器中我创建了一个DataTable,其中包含所有ExportOrdersViewModel属性,以及一行引用包含ExportOrdersItemViewModel属性的另一个DataTable。 parrent DataTable将被传递给工作簿。
在这里你可以看到我是如何做到的:
DataTable orders = new DataTable();
orders.Columns.Add("OrderID", typeof(string));
orders.Columns.Add("Items", typeof(DataTable));
orders.Columns.Add("IsShipped", typeof(bool));
DataTable items = new DataTable();
items.Columns.Add("TicketName", typeof(string));
items.Columns.Add("Quantity", typeof(int));
items.Columns.Add("Currency", typeof(string));
exportModels.ForEach(o => orders.Rows.Add(
o.Id,
(DataTable)GetItems(o.Items),
o.IsShipped
));
当我在调试模式下检查订单DataTable时,它包含对相应项DataTable的引用,但是当我传递给工作簿时,文件项行是空的。
以下是我创建文件的方法:
XLWorkbook workbook = new XLWorkbook();
workbook.Worksheets.Add(orders, "Orders");
Response.Clear();
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", "attachment;filename=\"HelloWorld.xlsx\"");
using (MemoryStream memoryStream = new MemoryStream())
{
workbook.SaveAs(memoryStream);
memoryStream.WriteTo(Response.OutputStream);
memoryStream.Close();
}
Response.End();
我想让它看起来像这样:https://aspblogs.blob.core.windows.net/media/muhanadyounis/Media/linqParentChild_615EF617.jpg
答案 0 :(得分:0)
最后,我找到了一个合适的解决方案。我每次都会在工作表中添加一个新表。我是这样做的:
//HELPER METHODS
private DataTable GetItems(ICollection<ExportOrdersItemViewModel> list)
{
var items = new DataTable();
items.Columns.Add(Resources.Names.OrderTicketName, typeof(string));
items.Columns.Add(Resources.Names.OrderEventName, typeof(string));
items.Columns.Add(Resources.Names.Quantity, typeof(int));
items.Columns.Add(Resources.Names.Currency, typeof(string));
items.Columns.Add(Resources.Names.PaymentCurrencyId, typeof(string));
items.Columns.Add(Resources.Names.UnitPrice, typeof(string));
items.Columns.Add(Resources.Names.PaymentUnitPrice, typeof(string));
list.ForEach(i => items.Rows.Add(i.TicketName, i.EventName, i.Quantity, i.CurrencyId, i.PaymentCurrencyId, i.UnitPrice, i.PaymentUnitPrice));
return items;
}
private void SetOrdersProperties(DataTable dataTable)
{
dataTable.Columns.Add(Resources.Names.OrderId, typeof(string));
dataTable.Columns.Add(Resources.Names.OrderDate, typeof(string));
dataTable.Columns.Add(Resources.Names.InvoicedDate, typeof(string));
dataTable.Columns.Add(Resources.Names.CustomerFirstname, typeof(string));
dataTable.Columns.Add(Resources.Names.CustomerLastName, typeof(string));
dataTable.Columns.Add(Resources.Names.CustomerEmail, typeof(string));
dataTable.Columns.Add(Resources.Names.CustomerPhone, typeof(string));
dataTable.Columns.Add(Resources.Names.ShipTo, typeof(string));
dataTable.Columns.Add(Resources.Names.ShippingStreet, typeof(string));
dataTable.Columns.Add(Resources.Names.City, typeof(string));
dataTable.Columns.Add(Resources.Names.ShippingPostalCode, typeof(string));
dataTable.Columns.Add(Resources.Names.ShippingCountry, typeof(string));
dataTable.Columns.Add(Resources.Names.IsShipped, typeof(string));
}
private void SetItemsProperties(DataTable dataTable)
{
dataTable.Columns.Add(Resources.Names.OrderTicketName, typeof(string));
dataTable.Columns.Add(Resources.Names.OrderEventName, typeof(string));
dataTable.Columns.Add(Resources.Names.Quantity, typeof(int));
dataTable.Columns.Add(Resources.Names.Currency, typeof(string));
dataTable.Columns.Add(Resources.Names.PaymentCurrencyId, typeof(string));
dataTable.Columns.Add(Resources.Names.UnitPrice, typeof(string));
dataTable.Columns.Add(Resources.Names.PaymentUnitPrice, typeof(string));
}
我使用这些方法创建包含项目的DataTable,并为订单和项目设置tableHeaders。 在下一段代码中是我创建文件的方式:
DataTable orders = new DataTable();
SetOrdersProperties(orders);
DataTable items = new DataTable();
SetItemsProperties(items);
XLWorkbook workbook = new XLWorkbook();
var workSheet = workbook.Worksheets.Add("Orders");
var index = 1;
exportModels.ForEach(o =>
{
orders.Rows.Add(
o.Id,
o.OrderDate,
o.InvoicedDate,
o.CustomerFirstName,
o.CustomerLastName,
o.CustomerEmail,
o.CustomerMobile,
o.ShippingTo,
o.ShippingStreet,
o.ShippingCity,
o.ShippingPostalCode,
o.ShippingCountry,
o.IsShipped ? "YES":"NO"
);
workSheet.Cell(index, 1).InsertTable(orders);
index += orders.Rows.Count+1;
orders = new DataTable();
SetOrdersProperties(orders);
workSheet.Cell(index, 2).InsertTable(GetItems(o.Items));
workSheet.Cell(index, 1).Value = Resources.Names.Tickets;
workSheet.Range(index, 1, index + o.Items.Count,1).Merge();
index += o.Items.Count()+1;
index++;
});
workSheet.Tables.ForEach(t => t.ShowAutoFilter = false);
workSheet.Style.Alignment.Vertical = XLAlignmentVerticalValues.Center;
workSheet.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
workSheet.Tables.ForEach(t => t.Theme = XLTableTheme.TableStyleLight13);