代码之家  ›  专栏  ›  技术社区  ›  Stephen Jennings

填充用于生成报表的通用视图模型

  •  0
  • Stephen Jennings  · 技术社区  · 16 年前

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

    我目前的方法是创建一个包含类型为 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;
    

    虽然这是可行的,但似乎效率低下。我将遍历整个结果集,以填充视图模型,然后视图将不得不再次遍历它来构建报告。

    我的问题是:有没有更简单的方法?如果我能让Linq查询返回 IEnumerable<IEnumerable<string>> 那我就用这条线吧” data.Rows = tickets “视图将能够循环通过这个本身。

    我想一定有更好的方法可以做到这一点,我不知道。

    2 回复  |  直到 16 年前
        1
  •  1
  •   Mathias F    16 年前

    如果你愿意使用反射,那么试试我在codeplex中的项目。 mvcrendermodel

    它以表格形式显示对象列表。

    我构建这个项目是为了更容易地调试,它通常对生产没有用处,但是如果您只有有限的流量,它应该是可以的。

        2
  •  0
  •   Stephen Jennings    16 年前

    这是我通过马西亚斯的建议提出的解决方案。不是世界上最快的东西,但现在足够快。

    我将视图模型更改为使用 IEnumerable 没有类型和标题字典:

    列表报告视图模型.cs

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

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

    报表控制器.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 );
    

    然后,视图将完成处理的工作,以搅动视图模型并填充表:

    文件管理系统

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