填充通用ViewModel以构建报告

时间:2009-06-10 19:33:10

标签: c# asp.net-mvc linq linq-to-entities

我需要生成几个报告,其中许多报告只是我数据库中的实体表。实体可以是任何类型,我不会总是需要整个实体。

我目前的方法是创建一个ViewModel,其中包含List<List<string>>类型的字段,该字段代表我的表,其中每一行都是一个单元格列表。然后,视图只需要枚举每行和每列来创建表。

public class ListReportViewModel
{
    public string Title;
    public List<string> Headings;
    public List<List<string>> Rows;
}

然后我有控制器代码来填充标题和行:

// Get the entities for the report
var tickets = ( from t in _db.Ticket.Include("Company").Include("Caller")
              select t );    

// Populate the column headings
data.Headings = new List<string>();
data.Headings.Add( "Ticket ID" );
data.Headings.Add( "Company" );
data.Headings.Add( "Caller" );
data.Headings.Add( "Reason for Call" );

// Temporary staging variables
List<List<string>> rows = new List<List<string>>();
List<string> row;

// Populate temporary variables
foreach ( var ticket in tickets )
{
    row = new List<string>();

    row.Add( ticket.TicketID.ToString() );
    row.Add( ticket.Company.Name );
    row.Add( ticket.Caller.FirstName + " " + ticket.Caller.LastName );
    row.Add( ticket.Subject );

    rows.Add( row );
}

// Populate ViewModel field
data.Rows = rows;

虽然这有效但似乎效率低下。我循环遍历整个结果集只是为了填充ViewModel,然后视图将不得不再次遍历它以构建报告。

我的问题:有更简单的方法吗?如果我可以让我的Linq查询返回IEnumerable<IEnumerable<string>>,那么我可以使用“data.Rows = tickets”这一行,视图就可以循环显示。

我认为必须有更好的方法来做到这一点,我不知道。

2 个答案:

答案 0 :(得分:1)

如果您愿意使用反射,请在codeplex mvcrendermodel

中试用我的项目

它将对象列表显示为表格。

我构建项目以便于调试,它通常对生产没有用,但如果你只有有限的流量,它应该没问题。

答案 1 :(得分:0)

这是我在查看Mathias的建议后想出的解决方案。这不是世界上最快的东西,但现在已经足够快了。

我将我的ViewModel更改为使用IEnumerable而不使用标题类型和字典:

ListReportViewModel.cs

public class ListReportViewModel
{
    public string Title;
    public Dictionary<string,string> Headings;
    public IEnumerable Data;
}

在我的控制器中,我以正常方式选择实体,并填充标题字典以定义我要报告的内容:

ReportController.cs

var data = new ListReportViewModel();

data.Title = "Closed Calls";

data.Headings = new Dictionary<string, string>();
data.Headings.Add( "TicketID", "ID" );
data.Headings.Add( "Company.Name", "Company" );
data.Headings.Add( "Caller.FirstName", "Caller" );
data.Headings.Add( "Subject", "Reason for Call" );
data.Headings.Add( "ClosedTime", "Closed" );
data.Headings.Add( "ClosedBy.LoginName", "Closed By" );

data.Data = ( from t in _db.Ticket.Include( "Company" ).Include( "Caller" ).Include( "ClosedBy" )
              where !t.Open
              orderby t.ClosedTime ascending
              select t );

return View( "list", data );

然后,处理的内容由视图完成,以便通过ViewModel流失并填充表格:

list.aspx

bool isFirstRow = true;
Type rowType = typeof( System.Data.Objects.DataClasses.EntityObject );
Type propType;
System.Reflection.PropertyInfo propInfo;
object propObject;
string[] propNames;

foreach ( var row in Model.Data )
{
    if ( isFirstRow )
    {
        // Get the type of entity we're enumerating through
        rowType = row.GetType();
        isFirstRow = false;
    }

    // Enumerate through the columns
    foreach ( var kvp in Model.Headings )
    {
        propNames = kvp.Key.Split( '.' );
        propObject = row;
        propType = rowType;

        // Drill down through the entity properties so we can
        // handle properties like "Ticket.Company.Name"
        foreach ( var propName in propNames )
        {
            try
            {
                propInfo = propType.GetProperty( propName );
                propObject = propInfo.GetValue( propObject, null );
                propType = propObject.GetType();
            }
            catch ( NullReferenceException ) { }
        }

        try
        {
            Response.Write( "<td>" + Html.Encode( propObject.ToString() ) + "</td>" );
        }
        catch ( NullReferenceException )
        {
            Response.Write( "<td>--</td>" );
        }

    }
}