代码改变世界

【分享】(性能优化)思考数据列表中“特殊的列”

2012-01-06 01:05  stevey  阅读(225)  评论(1编辑  收藏  举报

  数据列表在应用程序中十分常见和普遍,尤其是管理类的软件操作界面,如:一个待办列表,邮件列表,用户列表等。数据列表的数据源是由我们通过数据查询,逻辑运算,最终展示为列表。

  我们来看一种需求场景,假设列表中有一个“特殊的列“,它的数据不直接对应为数据库的列,或者是视图中的列,而是需要通过查询另外的关联表,通过计算得出,那么在绑定数据的时候,如何绑定上去呢?

假如:有一张表单表(tab_FormData),列如下:

      Id,FormId(表单Id),Title(标题),Content(内容)。。。

和一张任务表(tab_TaskInfo),列如下:

      Id,FormId(外键与tab_FormData的FormId),UserId(任务所有者Id),UserName(用户姓名),Comment(批示),Status(办理状态),CreateTime(任务创建时间)。。。

  当流程走到一个节点B时,一个表单可能对应着多个该节点的任务。如:该节点为【领导审批】节点,有三个领导做了批示(对应着任务表中三条记录),批示的内容分别为(圈阅,请张三领导阅,圈阅),当流转到下一节点【分发】时,需要补充张三领导,然后再回到【领导审批】节点,让张三领导去审批。那么在待办【分发】列表中,需要提示某一条公文是否有领导批示的不是圈阅的意见。如果存在,就在列表上标记出来,不存在就不标记。要显示的列表如下:有4列

  FormId,Title,Content,提醒()

   001      公文的标题   公文的内容  是

最后一列,是通过表单Id从任务表中查询得出。伪linq代码:

public static bool IsExist(string formId)

{

  var query=from t in ObjectContext.tab_TaskInfo

        where t.FormId=formId && t.NodeId=领导节点 && t.Comment!="圈阅"

        select t;

  return query.Count()>0;

}

在循环绑定列表的时候,每一行数据都需要去做上面的查询,以便绑定最后一列。

提问:有没有更好的解决方法,去绑定像上面这种情况的“特殊列”呢?

如果把”特殊列“的逻辑封装成一个方法,是比较直观的做法。在上述情况下,则带来的是多次查询数据库,性能有所损失。

解决方法:

  1.如果只查询一次数据库,就能得到所有的列,这样最好了。做表连接查询

  2.将特殊列的逻辑放在一个函数中,这样便于复杂逻辑处理,直观。这样这个”特殊列“就需要多次查询数据库。有些情况下,可能需要连接多张表才能得到结果。

 

给出另外一种思路:列表中除”特殊列“之外的进行(第一次查询),在把(第一次查询)相关的数据进行第二次查询,然后在内存中把这两次的查询结果处理拼接起来。

当然这个列表是需要分页显示的。给出linq伪代码:           

//获取和当前页相关的数据列表(第二次查询),第一个参数当前页的列表,返回当前页相关的任务列表
Func<IEnumerable<tab_FormData>, IEnumerable<tab_TaskInfo>> getGridContext = rows =>
{
return FormDataBLL.GetLeaderTasks(rows.Select(p => p.Formid).ToArray());//这里查询出符合条件的结果(t.NodeId=领导节点 && t.Comment!="圈阅")
};

 

//列筛选表达式
Func<tab_FormData, IEnumerable<tab_TaskInfo>, object> selector = (row, gridContext) =>//row表示当前行,gridContext表示当前页的相关数据列表
{
var hasLeaderComment = gridContext.Where(p => p.formid == row.formid)
.Count() > 0;//内存处理
return new
{
id = row.id,
formid = row.formid,
Title = row.Title,
Content = row.Content,
HasComment = hasLeaderComment
                };
};


页面绑定伪代码:

JQueryUI.GridRender<tab_FormData, tab_TaskInfo>(source, getGridContext, selector, context.Request, context.Response);

实现的关键代码:

var  viewPageList = pageData.ToList();//一页的数据,(第一次查询)
//重写行
if (viewPageList.Count > 0)
{
tempList = new List<object>();
foreach (var item in viewPageList)
{
var model = selector(item, viewPageList);
tempList.Add(model);
}
}

string jsonData = DataConvertUtility.ToJson(tempList);//得到最终的所有列,用于显示

 

总结:这样带有“特殊列”的列表,只需要查询两次数据库,就可以得到需要的结果,当然这是取一个平衡点,上述的当前页的相关的任务列表数据量不大。

好了,时间有点晚了,睡觉,下次再补充下,请各位同学谅解,如有疑问,提出来我们一起讨论,共同进步,谢谢!