在什么情况下,objectdatasource对象会多次调用selectmethod?

时间:2012-09-06 09:19:23

标签: asp.net gridview sharepoint-2010 objectdatasource

我正在使用带有SPGridView的ObjectDataSource(基于GridView的SharePoint控件),并查看日志,SelectMethod被调用九次 - 这是它真正需要的8倍。

我想知道是否有人确切地知道ObjectDataSource对象在什么条件下会调用Select方法,或者要检查的大量事项列表/关于优化它的任何建议?它是DataBound所以这意味着它全部归结为SPGridView?

我知道selectcount方法会调用它一次(as per this SO answer),但我真的不明白为什么它需要多次调用select方法。我在错误的步骤绑定了吗?在错误的步骤初始化?我也启用了分页,排序和过滤......任何提示都会很棒:)

编辑:我在事件中添加了一些日志代码,看起来GridView上的DataBinding事件被多次命中,这是否意味着内部SPGridView多次调用DataBind()?我调用的唯一DataBind()是用户控件中的Render事件,它只被引发一次。

记录跟踪:

ODS_Selecting
ODS_ObjCreating
ODS_Selecting
Gridview_DataBinding
ODS_Selecting
ODS_ObjCreating
ODS_Selecting
Gridview_DataBinding
GridView_RowDataBound
...
GridView_RowDataBound
ODS_Selecting
ODS_ObjCreating
ODS_Selecting
Gridview_DataBinding
GridView_RowDataBound
...
GridView_RowDataBound
ODS_Selecting
ODS_ObjCreating
ODS_Selecting
Gridview_DataBinding
GridView_RowDataBound
...
GridView_RowDataBound
ODS_Selecting
ODS_ObjCreating
ODS_Selecting
Gridview_DataBinding
GridView_RowDataBound
...
GridView_RowDataBound
ODS_Selecting
ODS_ObjCreating
ODS_Selecting
Gridview_DataBinding
GridView_RowDataBound
...
GridView_RowDataBound
ODS_Selecting
ODS_ObjCreating
ODS_Selecting
Gridview_DataBinding
GridView_RowDataBound
...
GridView_RowDataBound
ODS_Selecting
ODS_ObjCreating
ODS_Selecting
Gridview_DataBinding
GridView_RowDataBound
...
GridView_RowDataBound
ODS_Selecting
ODS_ObjCreating
ODS_Selecting
Gridview_DataBinding
GridView_RowDataBound
....
GridView_RowDataBound
ODS_Selecting
ODS_ObjCreating
ODS_Selecting
Gridview_DataBinding
GridView_RowDataBound
....
GridView_RowDataBound

而且,这里有很多代码!

的.ascx:

<SharePoint:SPGridView ID="appGridView" DataSourceID="appODS" AutoGenerateColumns="false" 
AllowPaging="true" PageSize="10" AllowSorting="true"
AllowFiltering="true" FilterDataFields=",,,,TimeElapsed,,," FilteredDataSourcePropertyName="FilterExpression" FilteredDataSourcePropertyFormat="{1} = '{0}'"
runat="server" />
<wc:ObjectDataSource ID="appODS" runat="server" />
<SharePoint:SPGridViewPager ID="appGridViewPager" runat="server" GridViewId="appGridView" />

.ascx.cs:

public partial class MyUserControl:UserControl     {

    //http://www.reversealchemy.net/blog/2009/05/01/building-a-spgridview-control-part-1-introducing-the-spgridview/
    //http://www.reversealchemy.net/2009/05/24/building-a-spgridview-control-part-2-filtering/

    protected override void OnInit(EventArgs e)
    {
        appODS.EnablePaging = true;
        appODS.SelectMethod = "GetMyDataTable";
        appODS.SelectCountMethod = "GetMyDataTableCount";
        appODS.StartRowIndexParameterName = "rowStart";
        appODS.MaximumRowsParameterName = "rowCount";

        appODS.SelectParameters.Add(new Parameter { Name = "myParam", DefaultValue = "test" });  
        appODS.TypeName = this.GetType().AssemblyQualifiedName;
        appODS.ObjectCreating += new ObjectDataSourceObjectEventHandler(appODS_ObjectCreating);

        appGridView.RowDataBound += new GridViewRowEventHandler(appGridView_RowDataBound);
        appODS.Filtering += new ObjectDataSourceFilteringEventHandler(appODS_Filtering);
        appGridView.Sorting += new GridViewSortEventHandler(appGridView_Sorting);
    }


    //https://stackoverflow.com/questions/1351578/spgridview-data-and-correct-method-of-ensuring-data-is-safe
    protected override void OnPreRender(EventArgs e)
    {
        if (!string.IsNullOrEmpty(appODS.FilterExpression))
        {
            appODS.FilterExpression = string.Format(
                appGridView.FilteredDataSourcePropertyFormat,
                appGridView.FilterFieldValue.Replace("'", "''"),
                appGridView.FilterFieldName
                );
        }

        base.OnPreRender(e);
    }


    private void appODS_ObjectCreating(object sender, ObjectDataSourceEventArgs e)
    {
        e.ObjectInstance = this;
    }

    protected sealed override void Render(HtmlTextWriter writer)
    {
        GenerateColumns();
        appGridView.DataBind();
        base.Render(writer);
    }

    public DataTable GetMyDataTable(string myParam, int rowStart, int rowCount)
    {
        DataTable dt = new DataTable();

        dt.Columns.Add("ID", typeof(Int32));
        // more columns here 
        dt.Columns.Add("TestColumn", typeof(decimal));


        List<Stuff> things = svc.GetStuff();


        foreach (Stuff thing in things)
        {
            dt.Rows.Add(
                thing.Blah, thing.Blah2);
        }

        return dt;
    }

    public int GetMyDataTableCount(string myParam)
    {
        return 10003; //faked out for now           
    }

    private void GenerateColumns()
    {
        BoundField column = new BoundField();
        column.DataField = "ID";
        column.SortExpression = "ID";
        column.HeaderText = "ID";            
        appGridView.Columns.Add(column);

        //more

        column = new BoundField();
        column.DataField = "TestColumn";
        column.SortExpression = "TestColumn";
        column.HeaderText = "TestColumn";
        appGridView.Columns.Add(column);

    }


    ////filtering
    protected sealed override void LoadViewState(object savedState)
    {
        base.LoadViewState(savedState);

        if (Context.Request.Form["__EVENTARGUMENT"] != null &&
             Context.Request.Form["__EVENTARGUMENT"].EndsWith("__ClearFilter__"))
        {
            // Clear FilterExpression
            ViewState.Remove("FilterExpression");
        }
    }

    private void appODS_Filtering(object sender, ObjectDataSourceFilteringEventArgs e)
    {
        ViewState["FilterExpression"] = ((ObjectDataSourceView)sender).FilterExpression;
    }

    private void appGridView_Sorting(object sender, GridViewSortEventArgs e)
    {
        if (ViewState["FilterExpression"] != null)
        {
            appODS.FilterExpression = (string)ViewState["FilterExpression"];
        }
    }

    private void appGridView_RowDataBound(object sender, GridViewRowEventArgs e)
    {
        if (sender == null || e.Row.RowType != DataControlRowType.Header)
        {
            return;
        }

        SPGridView grid = sender as SPGridView;

        if (String.IsNullOrEmpty(grid.FilterFieldName))
        {
            return;
        }

        // Show icon on filtered column
        for (int i = 0; i < grid.Columns.Count; i++)
        {
            DataControlField field = grid.Columns[i];

            if (field.SortExpression == grid.FilterFieldName)
            {
                Image filterIcon = new Image();
                filterIcon.ImageUrl = "/_layouts/images/filter.gif";
                filterIcon.Style[HtmlTextWriterStyle.MarginLeft] = "2px";

                // If we simply add the image to the header cell it will
                // be placed in front of the title, which is not how it
                // looks in standard SharePoint. We fix this by the code
                // below.
                Literal headerText = new Literal();
                headerText.Text = field.HeaderText;

                PlaceHolder panel = new PlaceHolder();
                panel.Controls.Add(headerText);
                panel.Controls.Add(filterIcon);

                e.Row.Cells[i].Controls[0].Controls.Add(panel);

                break;
            }
        }
    }
}

1 个答案:

答案 0 :(得分:0)

我最终通过甩掉反射器并进行更多挖掘来解决这个问题 - 事实证明我甚至不需要在Render方法中调用.DataBind(),因为SPGridView继承自BaseDataBoundControl,确保在必要时调用DataBind - 根据我在MSDN上的理解,它被称为OnPreRender。

事实证明,通过在Render事件中生成列(appGridView.Columns.Add(column);),每次我修改appGridView时,DataBind()方法最终再次被调用 - 所以Render事件是设置gridview Columns为时已晚,因为在那个阶段它已经完成所有已经完成的工作,并且每次添加新的时候都必须“重新绑定”以获取数据。

这是一个巨大的性能问题,如果你在how to set up a SPGridView with ObjectDataSource上关注其他不错的例子,你应该注意这一点。