如何从Queryable对象插入数据的列和行?下面列出了我到目前为止所拥有的。看来我可以将列名称放入电子表格中,但是我不确定如何使用我编写的方法插入值。
private IQueryable<ShippingRequest> GetRecordsFromDatabase()
{
var CurrentUserId = (int)Session["UserId"];
var results = db.ShippingRequests
.Where(r => r.UserId == CurrentUserId);
return results;
}
//Create the WorkSheet
ExcelWorksheet worksheet = excelPackage.Workbook.Worksheets.Add("FedEx Rates");
//get columns of table
var columnNames = typeof(ShippingRequest).GetProperties()
.Select(x => x.Name)
.ToArray();
int i = 0;
//Adding column name to worksheet
foreach (var col in columnNames)
{
i++;
worksheet.Cells[1, i].Value = col;
}
//Adding records to worksheet
int j;
for (i = 0; i<columnNames.Length; i++)
{
foreach (var item in db)
{
worksheet.Cells[i + 2, j + 1].Value = ???; //Not sure how to get this value
}
}
答案 0 :(得分:1)
因此,您获取了一些数据作为序列,并且希望将该序列的每个元素作为一行添加到表中。这些列都是ShippingRequests的所有可读公共属性。
让我们创建一个通用解决方案,该解决方案将添加任何列序列并显示某个类的任何对象序列。
通常,列的名称不必与所有属性的名称一一对应。有时您只想显示一些属性。有时您想创建不同的列名或显示不同的值。也许您不想将数据显示到excel工作表中,而是显示在另一种表中?
从表类定义列的可重用类可能类似于:
class Column<TSource>
{
public int Index {get; set;}
public string Name {get; set;}
public Func<TSource, object> PropertyValueSelector {get; set;}
public object GetValue(TSource source)
{
return this.PropertyValueSelector(source);
}
... // possible other properties, like: IsVisible, IsSortable, DisplayFormat?
}
显然,您想为ShippingRequests创建一个列序列,其中包含ShippingRequest的每个公共属性。列的名称是属性的标识符。索引并不重要。
以下函数将创建您的列序列:
public static IEnumerable<Column<TSource>> CreateColumns<TSource>()
where TSource : class
{
return typeof(TSource).GetProperties()
.Where(property => property.CanRead) // they must be at least readable
.Select( (propertyInfo, index) => new Column<TSource>
{
Index = index,
Name = propertyInfo.Name,
PropertyValueSelector = source => propertyInfo.GetValue(source);
});
}
获得数据和列后,我们便可以填写您的工作表:
void Fill<TSource>(this ExcelWorkSheet workSheet,
IEnumerable<Column<TSource>> columns,
IEnumerable<TSource> sourceData)
{
// TODO: clear worksheet?
//Add column names to worksheet
foreach (var column in columns)
{
worksheet.Cells[1, column.Index].Value = column.Name;
}
// add the source data
int nextRowIndex = 2;
foreach (var rowData in sourceData)
{
AddRow(workSheet, nextRowIndex, columns, rowData);
++nextRowIndex;
}
}
void AddRow<TSource> AddRow<TSource>(this ExcelWorkSheet workSheet,
int rowIndex,
IEnumerable<Column<TSource>> columns,
TSource rowData)
{
foreach (var column in columns)
{
var value = column.GetValue(rowData);
worksheet.Cells[rowIndex, column.Index].Value = value;
}
}
现在,有了这个,您的代码就很简单了:
var workSheet = ...
var columns = ...
var data = ...
worksheet.Fill(columns, data);
在您的情况下:
var worksheet = excelPackage.Workbook.Worksheets.Add("FedEx Rates");
var columns = CreateColumns<ShippingRequest>().ToList();
var shippingRequests = GetShippingRequests();
worksheet.Fill(columns, shippingRequests);
// Bam! Done!
令人高兴的是,您可以使用该代码用任何类的数据填充工作表。
例如,我有一班学生,我想显示100名最年轻学生中的一些列。
// I only want to show the following columns of students:
var studentColumns = new Column<Student>
{
new Column {Index = 1, Name = "Id", PropertyValueSelector = student => student.Id },
new Column {Index = 3, Name = "Birthday", PropertyValueSelector = student => student.Id }
new Column {Index = 2, Name = "Student Name", PropertyValueSelector = student =>
String.Format("{0} {1} {2}", student.FirstName,
student.MiddleName,
student.FamilyName} },
};
// I only want 100 youngest students:
var studentsToDisplay = GetStudents()
.OrderByDescending(student => student.BirthDay)
.Take(100)
.ToList();
// filling the worksheet is only two lines:
var worksheet = excelPackage.Workbook.Worksheets.Add("Young Students");
worksheet.Fill(studentColumns, studentsToDisplay);