简体   繁体   English

将列和行从IQueryable对象插入电子表格

[英]Insert Columns and Rows into spreadsheet from IQueryable object

How do I insert the columns and rows of data from an Queryable object? 如何插入来自Queryable对象的数据的列和行? What I have so far is listed below. 下面列出了我到目前为止所拥有的。 It seems I can get the column names into the spread sheet but Im not sure how to insert the values using the method I have written. 看来我可以将列名称放入电子表格中,但是我不确定如何使用我编写的方法插入值。


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
    }
}

So you fetched some data as a sequence, and you want every element of this sequence to be added as one row to your table. 因此,您获取了一些数据作为序列,并且希望将该序列的每个元素作为一行添加到表中。 The columns are all readable public properties of ShippingRequests. 这些列都是ShippingRequests的所有可读公共属性。

Let's create a generic solution that will add any sequence of columns and show any sequence of objects of some class. 让我们创建一个通用解决方案,它将添加任何列序列并显示某个类的对象的任何序列。

Quite often, the names of the columns don't have to fit one-on-one to the names of all your properties. 通常,列的名称不必一对一地适合所有属性的名称。 Sometimes you want to show only some properties. 有时您只想显示一些属性。 Sometimes you want to create different column names or show different values. 有时您想创建不同的列名或显示不同的值。 Maybe you don't want to show your data to an excel sheet, but to a different kind of table? 也许您不想将数据显示到Excel工作表中,而是显示在另一种表中?

A reusable class to define columns from some table class could be something like: 从表类定义列的可重用类可能类似于:

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?
}

Apparently, you want to create a sequence of columns for your ShippingRequests containing every public property of ShippingRequest. 显然,您想为您的ShippingRequests创建一个列序列,其中包含ShippingRequest的每个公共属性。 The name of the column is the identifier of the property. 列的名称是属性的标识符。 The index is not important. 索引并不重要。

The following function will create your sequence of Columns: 以下函数将创建您的列序列:

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);
        });
}

Once we got our data and our columns, we can fill your worksheet: 获得数据和列后,我们可以填写您的工作表:

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;
    }
}

Now that you've got this, your code will be easy: 有了这个,您的代码就很容易了:

var workSheet = ...
var columns = ...
var data = ...
worksheet.Fill(columns, data);

In your case: 在您的情况下:

var worksheet = excelPackage.Workbook.Worksheets.Add("FedEx Rates");
var columns = CreateColumns<ShippingRequest>().ToList();
var shippingRequests = GetShippingRequests();
worksheet.Fill(columns, shippingRequests);
// Bam! Done!

The nice thing is that you can use the code to fill worksheets with data from any class. 令人高兴的是,您可以使用该代码用任何类的数据填充工作表。

For example, I have a class Student and I want to show some columns of the 100 youngest students. 例如,我有一班学生,我想显示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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM