如何为组合框只获取一次我的数据源?

时间:2012-04-07 08:16:53

标签: c# asp.net performance web-services telerik

我使用telerik:RadComboBox

像这样:

<telerik:RadComboBox runat="server" ID="RadComboBox1"  EnableLoadOnDemand="true"
                                            ShowMoreResultsBox="true" EnableVirtualScrolling="true" CollapseDelay="0" Culture="ar-EG" ExpandDelay="0" Filter="StartsWith" ItemsPerRequest="100"
                                            MarkFirstMatch="true" Skin="Outlook" ValidationGroup="L" Width="202px" EnableAutomaticLoadOnDemand="True"
                                            EmptyMessage="-Enter user name-"
                                            EnableItemCaching="true" >
                                            <WebServiceSettings Path="../WebService/Employees.asmx" Method="LoadData" />


和我的网络服务:

 [System.Web.Script.Services.ScriptService]
    public class Employees : System.Web.Services.WebService
    {

        [WebMethod(EnableSession = true)]  
            public RadComboBoxData LoadData(RadComboBoxContext context)
                {

                RadComboBoxData result = new RadComboBoxData();
                DataTable dt = FollowsDAL.GetAllEmployees();

                var allEmployees = from r in dt.AsEnumerable()

                                   orderby r.Field<string>("name")

                                   select new RadComboBoxItemData
                                   {
                                       Text = r.Field<string>("name").ToString().TrimEnd()
                                   };
                string text = context.Text;
                if (!String.IsNullOrEmpty(text))
                {
                    allEmployees = allEmployees.Where(item => item.Text.StartsWith(text));
                }
                //Perform the paging
                // - first skip the amount of items already populated
                // - take the next 10 items
                int numberOfItems = context.NumberOfItems;
                var employees = allEmployees.Skip(numberOfItems).Take(100);


                result.Items = employees.ToArray();


                int endOffset = numberOfItems + employees.Count();
                int totalCount = allEmployees.Count();

                //Check if all items are populated (this is the last page)
                if (endOffset == totalCount)
                    result.EndOfItems = true;

                //Initialize the status message
                result.Message = String.Format("Items <b>1</b>-<b>{0}</b> out of <b>{1}</b>",
                                               endOffset, totalCount);

                return result;
            }}

我的问题是:

虽然此控制速度非常快,但每次我输入特定名称时,它都会在数据表20000中提取dt员工!!!

每个角色。

我的问题是:

  • 这种不良行为怎么这么快?
  • 有没有办法让所有员工只有一次?
  • 如何提升表现?

5 个答案:

答案 0 :(得分:4)

使用服务器端过滤总是更好,因为您不需要将20000条记录检索到网络服务器以使用10或20个项目返回。

http://demos.telerik.com/aspnet-ajax/combobox/examples/populatingwithdata/autocompletesql/defaultcs.aspx

答案 1 :(得分:2)

您的DAL应该有一种方法来根据发送的文本过滤结果,然后将它们添加到组合框中。我的DAL是Telerik OpenAccess ORM(Linq2SQL),但您也可以编写存储过程来过滤结果。

以下是我填充radcombobox的一个asmx服务示例:

    [WebMethod]
    public RadComboBoxData FindEmployee(RadComboBoxContext context)
    {
        RadComboBoxData comboData = new RadComboBoxData();

        using (DataBaseContext dbc = new DataBaseContext())
        {
            IQueryable<Employee> Employees = dbc.FindEmployee(context.Text);

            int itemOffset = context.NumberOfItems;
            int endOffset = Math.Min(itemOffset + 10, Employees.Count());
            List<RadComboBoxItemData> result = new List<RadComboBoxItemData>();

            var AddingEmployees = Employees.Skip(itemOffset).Take(endOffset - itemOffset);
            foreach (var Employee in AddingEmployees)
            {
                RadComboBoxItemData itemData = new RadComboBoxItemData();
                itemData.Text = Employee.Person.FullName;
                itemData.Value = Employee.EmployeeID.ToString();

                result.Add(itemData);
            }


            comboData.EndOfItems = endOffset == Employees.Count();
            comboData.Items = result.ToArray();
            if (Employees.Count() <= 0)
                comboData.Message = "No matches";
            else
                comboData.Message = String.Format("Items <b>1</b>-<b>{0}</b> out of <b>{1}</b>", endOffset, Employees.Count());
            return comboData;
        }
    }

如果您想知道我的FindEmployee方法是什么:

public IQueryable<Employee> FindEmployee(string SearchString, bool IncludeInactive = false)
    {
        return from e in this.Employees
               where
                    (e.EmployeeID.ToString() == SearchString ||
                     e.Person.FirstName.Contains(SearchString) ||
                     e.Person.MiddleName.Contains(SearchString) ||
                     e.Person.LastName.Contains(SearchString) ||
                     (e.Person.FirstName + " " + e.Person.LastName).Contains(SearchString) ||
                     (e.Person.FirstName + " " + e.Person.MiddleName).Contains(SearchString) ||
                     (e.Person.FirstName + " " + e.Person.MiddleName + " " + e.Person.LastName).Contains(SearchString)) &&
                    ((e.Inactive == false || e.Inactive == null) && IncludeInactive == false)
               select e;
    }

答案 2 :(得分:1)

我会创建一个方法来加载数据库中的值,然后将它们存储在缓存中。对此方法的后续调用应返回缓存版本。然后将DataSource设置为此方法。这应该会给你一个非常好的性能提升。

http://msdn.microsoft.com/en-us/library/system.web.caching.cache.aspx

答案 3 :(得分:1)

我认为你的解决方案应该是@PraVn和@nurgent的混合答案。编写一个存储过程,按search字符串过滤记录。让您的DAL使用从现有网络方法调用的方法调用此SP public RadComboBoxData LoadData(RadComboBoxContext context)

答案 4 :(得分:1)

根据我的理解,为了相同的目的而一遍又一遍地向数据库发送请求对于应用程序运行状况不利。

基本上有两种方法可以使这个过程快速进行。

  
      
  1. 从DataBase以DataTable的形式提供数据。
  2.   
  3. 从DataBase以DataSet的形式提供数据。
  4.   

DataTable方法

在表单加载期间从Database获取所有记录。保留在ViewState而非Session中。请注意这一点。访问下面的数据.. 现在访问ViewStateType Cast它并访问下面提到的功能。

public static class GetFilteredData
{
    public static DataTable FilterDataTable(this DataTable Dt, string FilterExpression)
    {
        using (DataView Dv = new DataView(Dt))
        {
            Dv.RowFilter = FilterExpression;
            return Dv.ToTable();
        }
    }
}


DataTableObject.FilterDataTable("Search Expression or your string variable")

这将返回DataTable。在没有任何DataBase跳闸的情况下将数据重新分配给控件。每当必须过滤记录时执行此步骤。

数据集方法

此过程将从您的数据库发送26 DataTable。我知道它看起来很沉重。但正如您已经提到的那样,总记录将是25,000。因此,所有这些记录将在这些表之间进行划分。请参阅下面的解释。

ComboBox DataField Text column可以有26个不同的Start With字符。您必须根据Start with字符划分这些记录。用A记录开头将插入第一张表。以B开头的记录将被插入到第二个表中,以C开头的记录将被插入到第三个表中,依此类推,直到用Z开始的记录将被插入到第26个表中。

请注意,您的UDT查询最初将用于插入Local Temporary Table中的所有记录。这个Local Temporary Table将进一步包含26个基于Start With Character的选择语句。

以下是Sample Stored Proc。

Create Proc ProcName
As

Create Table #Temp
(
    ColumnName Varchar(50)
)

Insert into #Temp(ColumnName)
Select ColumnName from YourTableName

Select ColumnName From #Temp Where ColumnName like 'a%'
Select ColumnName From #Temp Where ColumnName like 'b%'
Select ColumnName From #Temp Where ColumnName like 'c%'
--UpTo Z

现在,最后您有26 Tables,数据将从您的BLL返回为DataSet。 仅在ViewState中保留它。现在将过滤数据,请使用下面提到的功能。

public static class GetFilteredData
{
    public static DataTable FilterDataTable(this DataSet Dt, string FilterExpression)
    {
        string Lowercase = FilterExpression.ToLower();
        Int16 TableID = 0;
        if (Lowercase.StartsWith("a"))
        {
            TableID = 0;
        }
        else if (Lowercase.StartsWith("b"))
        {
            TableID = 1;
        }
        else if (Lowercase.StartsWith("c"))
        {
            TableID = 2;
        }
        //upTo Z
        using (DataView Dv = new DataView(Dt.Tables[TableID]))
        {
            Dv.RowFilter = FilterExpression;
            return Dv.ToTable();
        }
    }
}

所以我们理解使用DataSet Technique的重要性在于,记录进一步分为表格中的子节点。您的Search expression将在Splitted Nodes DataSet而不是Original DataSet上实施。


原始查询中提到的代码修改

仅在Web应用程序/网站中添加以下内容。

public static class GetFilteredData
{
    public static DataTable FilterDataTable(this DataTable Dt, string FilterExpression)
    {
        using (DataView Dv = new DataView(Dt))
        {
            Dv.RowFilter = FilterExpression;
            return Dv.ToTable();
        }
    }
}

WebForm本身添加以下属性。如果Property为空,则以下ViewState将从数据库返回结果集。否则,它将仅返回ViewState保留的数据。

public DataTable Employees
{
    get
    {
        if (ViewState["Employees"] == null)
        {
            return FollowsDAL.GetAllEmployees();
        }
        return (DataTable)ViewState["Employees"];
    }
    set
    {
        ViewState["Employees"] = value;
    }
}

现在,您可以在ViewState中访问此WebFormCombobox可以控制DataSet。根据我的理解,你应该选择WebService方法。

请注意,在此上下文中不需要{{1}}。