1

私が使う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" />


と私のWebサービス:

 [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!!!

すべての文字で。

私の質問は:

  • この悪い振る舞いでこんなに速いの?
  • すべての従業員を一度だけ取得する方法はありますか?
  • パフォーマンスを向上させる方法は?
4

5 に答える 5

4

10個または20個のアイテムを使用して返すために、20000レコードをWebサーバーに取得する必要がないため、サーバー側のフィルタリングを使用することをお勧めします。

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

于 2012-04-07T08:43:41.583 に答える
2

DAL には、送信されたテキストに基づいて結果をフィルター処理するメソッドが必要です。次に、それらをコンボボックスに追加します。私の DAL は Telerik OpenAccess ORM (Linq2SQL) ですが、ストアド プロシージャを記述して結果をフィルタリングすることもできます。

以下は、radcombobox を生成する asmx サービスの 1 つの例です。

    [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;
    }
于 2012-04-10T13:28:46.213 に答える
1

私の理解によると、同じ目的でデータベースにリクエストを何度も送信することは、アプリケーションの状態に良くありません。

プロセスを高速化するには、基本的に2つの方法があります。

  1. データベースからDataTableの形式でデータを取得します。
  2. データベースからDataSetの形式でデータを取得します。

DataTableアプローチ

Databaseフォームの読み込み中にからすべてのレコードを取得します。ViewStateではなく、で保存しSessionます。この点にご注意ください。以下のようにデータにアクセスします。次に、にアクセスしViewStateます。Type 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。データベースがトリップすることなく、データをコントロールに再割り当てします。レコードをフィルタリングする必要があるときはいつでも、このステップを実行してください。

DataSetアプローチ

このプロセスは26 DataTableデータベースから送信されます。私はそれが非常に重く見えることを知っています。しかし、すでに述べたように、合計レコードは25,000になります。したがって、これらのレコードはすべて、これらのテーブルに分割されます。以下の説明をご覧ください。

ComboBox DataField Text column26の異なるStart With文字を持つことができます。Start withこれらのレコードを文字に従って分割する必要があります。Aで始まるレコードが最初のテーブルに挿入されます。Bで始まるレコードは2番目のテーブルに挿入され、Cで始まるレコードは3番目のテーブルに挿入され、Zで始まるレコードが26番目のテーブルに挿入されるまで続きます。

UDTクエリは元々、すべてのレコードをに挿入するために使用されることに注意してくださいLocal Temporary Table。これLocal Temporary Tableには、StartWithCharacterに基づいた26個のselectステートメントがさらに含まれます。

以下は、サンプルのストアドプロシージャです。

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

これで、最終的にデータがBLLから26 Tables返されます。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は、レコードがテーブルのforでサブノードにさらに分割されるということです。ではなく、に実装Search expressionされます。Splitted NodesDataSetOriginal DataSet


元のクエリに記載されているコードの変更

Webアプリケーション/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。以下は、がnullPropertyの場合にデータベースからの結果セットを返します。それ以外の場合は、保存されたデータのみViewStateを返します。ViewState

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

今、あなたはあなたがコントロールできるあなたのでこれViewStateにアクセスすることができます。私の理解によると、あなたはアプローチに行くべきです。WebFormComboboxDataSet

WebServiceこのコンテキストでは必須ではないことに注意してください。

于 2012-04-12T02:24:23.857 に答える
1

データベースから値をロードし、それらをキャッシュに保存するメソッドを作成します。その後このメソッドを呼び出すと、キャッシュされたバージョンが返されます。次に、DataSourceをこのメソッドに設定します。それはあなたに非常に素晴らしいパフォーマンスの向上を与えるはずです。

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

于 2012-04-08T05:15:33.283 に答える
1

あなたの解決策は、@PraVn と @nurgent による回答を組み合わせたものであるべきだと思います。レコードを文字列でフィルタリングするストアド プロシージャを作成しsearchます。既存の Web メソッドから呼び出されるメソッドを使用して、DAL にこの SP を呼び出させるpublic RadComboBoxData LoadData(RadComboBoxContext context)

于 2012-04-11T13:26:07.203 に答える