导出到 Excel - LINQ - 在 .ToList() 中包含外键值?
Export to Excel - LINQ - Include ForeignKey values in .ToList()?
我正在尝试通过 EPPlus 库向我的 MVC5/Code-First Entity Framework 应用程序添加 Excel 导出功能。在我的导出 View
中,我用每个 INV_Assets
模型属性填充了一个 MultiSelectList
。然后将这些传递到我的 ExportController
中以指定要导出模型的哪些字段。
我已经将 Headers(通过 MultiSelectList
)加载到 Excel 的第 1 行,并将我的 INV_Assets
模型中的数据导出到 excel 通过 EPPlus LoadFromCollection()
如下(示例):
代码:
[HttpPost]
public ActionResult ExportUsingEPPlus(ExportAssetsViewModel model)
{
ExcelPackage package = new ExcelPackage();
var ws = package.Workbook.Worksheets.Add("TestExport");
var exportFields = new List<string>();
foreach (var selectedField in model.SelectedFields)
{
// Adds selected fields to [exportFields] List<string>
exportFields.Add(model.ListOfExportFields.First(s => s.Key == selectedField).Value);
}
{
ws.Cells[1, i + 1].Value = exportFields[i].ToString();
}
var membersToShow = typeof(INV_Assets).GetMembers().Where(p => exportFields.Contains(p.Name)).ToArray();
ws.Cells["A2"].LoadFromCollection(_db.INV_Assets.ToList(), false, TableStyles.None, BindingFlags.Default, membersToShow);
var memoryStream = new MemoryStream();
package.SaveAs(memoryStream);
string fileName = "Exported-InventoryAssets-" + DateTime.Now + ".xlsx";
string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
memoryStream.Position = 0;
return File(memoryStream, contentType, fileName);
}
输出:
我仍然遇到的唯一问题是模型中的 ForeignKey
字段。例如,[Status]
在我的 INV_Assets
模型中定义为:
[Required]
public int Status_Id { get; set; }
[ForeignKey("Status_Id")]
public virtual INV_Statuses Status { get; set; }
当当前导出执行时,AVAILABLE
/RECYCLED
中的 [Status]
列在每个单元格中都包含 "InventoryTracker.Models.INV_Statuses"
,而不是说 AVAILABLE
/RECYCLED
对于每条导出的记录。
任何人都可以深入了解如何不仅导出直接 INV_Assets
字段,而且 Model, Location, Status, Vendor, Manufacturer, and Type
的 ForeignKey
值也导出到 Excel 中吗?
我读了一些书,认为 Include()
方法可行,但运气不好。 (示例)[Type]
使用以下代码在所有记录单元格中仍显示 InventoryTracker.Models.INV_Types
:
ws.Cells["A2"].LoadFromCollection(_db.INV_Assets.Include("Model").Include("Manufacturer").Include("Type").Include("Status").Include("Vendor").ToList(), false, TableStyles.None, BindingFlags.Default, membersToShow);
编辑:
我将 using System.Data.Entity
添加到我的 ExportController
中,这允许编译以下内容:
ws.Cells["A2"].LoadFromCollection(_db.INV_Assets.Include(m => m.Model.model_description).Include(m => m.Manufacturer.manufacturer_description).Include(m => m.Type.type_description).Include(m => m.Status.status_description).Include(m => m.Vendor.vendor_name).ToList(), false, TableStyles.None, BindingFlags.Default, membersToShow);
我认为这可以解决问题,但在执行过程中我收到:
InvalidOperationException was unhandled by user code.
An exception of type 'System.InvalidOPerationException' occurred in EntityFramework.SqlServer.dll but was not handled in user code.
Additional Information: A specified Include path is not valid. The EntityType 'InventoryTracker.DAL.INV_Models' does not declare a naviation property with the name 'model_description'.
我不明白为什么会以这种方式标记。 INV_Assets
与 INV_Models
的关系定义如下:
public int Model_Id { get; set; }
[ForeignKey("Model_Id")]
public virtual INV_Models Model { get; set; }
和INV_Models定义为:
public class INV_Models
{
public int Id { get; set; }
[Required(ErrorMessage = "Please enter a Model Description.")]
public string model_description { get; set; }
[Required]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")]
public DateTime created_date { get; set; }
[Required]
public string created_by { get; set; }
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")]
public DateTime? modified_date { get; set; }
public string modified_by { get; set; }
}
谁能发现我在 Include()
上做错了什么?
EDIT2:
感谢Eric J的建议,问题已解决!在我想要的每个模型上添加了一个 ToString()
覆盖,以确保值通过而不仅仅是 object 类型:
public class INV_Models
{
public override string ToString()
{
return this.model_description;
}
}
public class INV_Manufacturers
{
public override string ToString()
{
return this.manufacturer_description;
}
}
public class INV_Locations
{
public override string ToString()
{
return this.location_dept + "|" + this.location_room;
}
}
public class INV_Vendors
{
public override string ToString()
{
return this.vendor_name;
}
}
public class INV_Types
{
public override string ToString()
{
return this.type_description;
}
}
public class INV_Statuses
{
public override string ToString()
{
return this.status_description;
}
}
ExportController:
[HttpPost]
public ActionResult ExportUsingEPPlus(ExportAssetsViewModel model)
{
ExcelPackage package = new ExcelPackage();
var ws = package.Workbook.Worksheets.Add("TestExport");
var exportFields = new List<string>();
foreach (var selectedField in model.SelectedFields)
{
// Adds selected fields to [exportFields] List<string>
exportFields.Add(model.ListOfExportFields.First(s => s.Key == selectedField).Value);
}
// Loops to insert column headings into Row 1 of Excel
for (int i = 0; i < exportFields.Count(); i++)
{
ws.Cells[1, i + 1].Value = exportFields[i].ToString();
}
var membersToShow = typeof(INV_Assets).GetMembers().Where(p => exportFields.Contains(p.Name)).ToArray();
ws.Cells["A2"].LoadFromCollection(_db.INV_Assets.ToList(), false, TableStyles.None, BindingFlags.Default, membersToShow);
var membersToShow = typeof(INV_Assets).GetMembers().Where(p => exportFields.Contains(p.Name)).ToArray();
var memoryStream = new MemoryStream();
package.SaveAs(memoryStream);
string fileName = "Exported-InventoryAssets-" + DateTime.Now + ".xlsx";
string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
memoryStream.Position = 0;
return File(memoryStream, contentType, fileName);
}
并输出Excel文件:
When the current export executes though, instead of getting say AVAILABLE/RECYCLED, the [Status] column in excel contains "InventoryTracker.Models.INV_Statuses" in every cell for each record exported.
这就是在 INV_Statuses.
的实例上调用 System.Object.ToString() 时得到的结果
尝试覆盖 class:
中的 ToString()
public class INV_Statuses
{
public override string ToString()
{
// TODO: Return whatever you would like to have appear in Excel
}
// Rest of the class here
}
我正在尝试通过 EPPlus 库向我的 MVC5/Code-First Entity Framework 应用程序添加 Excel 导出功能。在我的导出 View
中,我用每个 INV_Assets
模型属性填充了一个 MultiSelectList
。然后将这些传递到我的 ExportController
中以指定要导出模型的哪些字段。
我已经将 Headers(通过 MultiSelectList
)加载到 Excel 的第 1 行,并将我的 INV_Assets
模型中的数据导出到 excel 通过 EPPlus LoadFromCollection()
如下(示例):
代码:
[HttpPost]
public ActionResult ExportUsingEPPlus(ExportAssetsViewModel model)
{
ExcelPackage package = new ExcelPackage();
var ws = package.Workbook.Worksheets.Add("TestExport");
var exportFields = new List<string>();
foreach (var selectedField in model.SelectedFields)
{
// Adds selected fields to [exportFields] List<string>
exportFields.Add(model.ListOfExportFields.First(s => s.Key == selectedField).Value);
}
{
ws.Cells[1, i + 1].Value = exportFields[i].ToString();
}
var membersToShow = typeof(INV_Assets).GetMembers().Where(p => exportFields.Contains(p.Name)).ToArray();
ws.Cells["A2"].LoadFromCollection(_db.INV_Assets.ToList(), false, TableStyles.None, BindingFlags.Default, membersToShow);
var memoryStream = new MemoryStream();
package.SaveAs(memoryStream);
string fileName = "Exported-InventoryAssets-" + DateTime.Now + ".xlsx";
string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
memoryStream.Position = 0;
return File(memoryStream, contentType, fileName);
}
输出:
我仍然遇到的唯一问题是模型中的 ForeignKey
字段。例如,[Status]
在我的 INV_Assets
模型中定义为:
[Required]
public int Status_Id { get; set; }
[ForeignKey("Status_Id")]
public virtual INV_Statuses Status { get; set; }
当当前导出执行时,AVAILABLE
/RECYCLED
中的 [Status]
列在每个单元格中都包含 "InventoryTracker.Models.INV_Statuses"
,而不是说 AVAILABLE
/RECYCLED
对于每条导出的记录。
任何人都可以深入了解如何不仅导出直接 INV_Assets
字段,而且 Model, Location, Status, Vendor, Manufacturer, and Type
的 ForeignKey
值也导出到 Excel 中吗?
我读了一些书,认为 Include()
方法可行,但运气不好。 (示例)[Type]
使用以下代码在所有记录单元格中仍显示 InventoryTracker.Models.INV_Types
:
ws.Cells["A2"].LoadFromCollection(_db.INV_Assets.Include("Model").Include("Manufacturer").Include("Type").Include("Status").Include("Vendor").ToList(), false, TableStyles.None, BindingFlags.Default, membersToShow);
编辑:
我将 using System.Data.Entity
添加到我的 ExportController
中,这允许编译以下内容:
ws.Cells["A2"].LoadFromCollection(_db.INV_Assets.Include(m => m.Model.model_description).Include(m => m.Manufacturer.manufacturer_description).Include(m => m.Type.type_description).Include(m => m.Status.status_description).Include(m => m.Vendor.vendor_name).ToList(), false, TableStyles.None, BindingFlags.Default, membersToShow);
我认为这可以解决问题,但在执行过程中我收到:
InvalidOperationException was unhandled by user code.
An exception of type 'System.InvalidOPerationException' occurred in EntityFramework.SqlServer.dll but was not handled in user code.
Additional Information: A specified Include path is not valid. The EntityType 'InventoryTracker.DAL.INV_Models' does not declare a naviation property with the name 'model_description'.
我不明白为什么会以这种方式标记。 INV_Assets
与 INV_Models
的关系定义如下:
public int Model_Id { get; set; }
[ForeignKey("Model_Id")]
public virtual INV_Models Model { get; set; }
和INV_Models定义为:
public class INV_Models
{
public int Id { get; set; }
[Required(ErrorMessage = "Please enter a Model Description.")]
public string model_description { get; set; }
[Required]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")]
public DateTime created_date { get; set; }
[Required]
public string created_by { get; set; }
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")]
public DateTime? modified_date { get; set; }
public string modified_by { get; set; }
}
谁能发现我在 Include()
上做错了什么?
EDIT2:
感谢Eric J的建议,问题已解决!在我想要的每个模型上添加了一个 ToString()
覆盖,以确保值通过而不仅仅是 object 类型:
public class INV_Models
{
public override string ToString()
{
return this.model_description;
}
}
public class INV_Manufacturers
{
public override string ToString()
{
return this.manufacturer_description;
}
}
public class INV_Locations
{
public override string ToString()
{
return this.location_dept + "|" + this.location_room;
}
}
public class INV_Vendors
{
public override string ToString()
{
return this.vendor_name;
}
}
public class INV_Types
{
public override string ToString()
{
return this.type_description;
}
}
public class INV_Statuses
{
public override string ToString()
{
return this.status_description;
}
}
ExportController:
[HttpPost]
public ActionResult ExportUsingEPPlus(ExportAssetsViewModel model)
{
ExcelPackage package = new ExcelPackage();
var ws = package.Workbook.Worksheets.Add("TestExport");
var exportFields = new List<string>();
foreach (var selectedField in model.SelectedFields)
{
// Adds selected fields to [exportFields] List<string>
exportFields.Add(model.ListOfExportFields.First(s => s.Key == selectedField).Value);
}
// Loops to insert column headings into Row 1 of Excel
for (int i = 0; i < exportFields.Count(); i++)
{
ws.Cells[1, i + 1].Value = exportFields[i].ToString();
}
var membersToShow = typeof(INV_Assets).GetMembers().Where(p => exportFields.Contains(p.Name)).ToArray();
ws.Cells["A2"].LoadFromCollection(_db.INV_Assets.ToList(), false, TableStyles.None, BindingFlags.Default, membersToShow);
var membersToShow = typeof(INV_Assets).GetMembers().Where(p => exportFields.Contains(p.Name)).ToArray();
var memoryStream = new MemoryStream();
package.SaveAs(memoryStream);
string fileName = "Exported-InventoryAssets-" + DateTime.Now + ".xlsx";
string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
memoryStream.Position = 0;
return File(memoryStream, contentType, fileName);
}
并输出Excel文件:
When the current export executes though, instead of getting say AVAILABLE/RECYCLED, the [Status] column in excel contains "InventoryTracker.Models.INV_Statuses" in every cell for each record exported.
这就是在 INV_Statuses.
的实例上调用 System.Object.ToString() 时得到的结果尝试覆盖 class:
中的 ToString()public class INV_Statuses
{
public override string ToString()
{
// TODO: Return whatever you would like to have appear in Excel
}
// Rest of the class here
}