Я пытаюсь добавить функциональность Excel Export в мое приложение MVC5/Code-First Entity Framework через библиотеку EPPlus. На моем Экспорт View
Я заполнил MultiSelectList
с каждой из моих INV_Assets
свойств модели. Затем они передаются в мой ExportController
, чтобы указать, какие поля модели должны быть экспортированы.Экспорт в Excel - LINQ - включение значений ForeignKey в .ToList()?
Я получил заголовки (с помощью MultiSelectList
), чтобы загрузить в Row1 из Excel и данные из моей INV_Assets
модели для экспорта, чтобы преуспеть с помощью 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]
столбец в Excel содержит "InventoryTracker.Models.INV_Statuses"
в каждой ячейке для каждой записи на экспорт.
Может ли кто-нибудь предложить понять, как получить не только прямые поля INV_Assets
, но и значения ForeignKey
для Model, Location, Status, Vendor, Manufacturer, and Type
также в Excel?
Я прочитал и подумал, что метод Include()
будет работать, но не повезло. [Type]
по-прежнему отображается InventoryTracker.Models.INV_Types
во всех звукозаписывающих клетках, используя следующий код (Ex.):
ws.Cells["A2"].LoadFromCollection(_db.INV_Assets.Include("Model").Include("Manufacturer").Include("Type").Include("Status").Include("Vendor").ToList(), false, TableStyles.None, BindingFlags.Default, membersToShow);
EDIT:
я добавил 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 «s, проблема решена! Добавлен ToString()
переопределение на каждом из моих желаемых моделей, чтобы обеспечить значение пришли через а не только тип объекта:
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 файл:
Спасибо Эрик, который сделал трюк! - показано выше в EDIT2. –
Рад, что все получилось. –