Linqデータソース、GridViewソート

18770 ワード

最近Linqにハマって、ASPをやっています.NETのプロジェクトでは,元のDataTabのデータソースもLinq方式で取得したデータソース,すなわちIEnumerableの一例に置き換えた.GridViewにバインドすると、ソートの問題が発生します.大回りしてやっと分かった.NET 3.5で依頼した書き方で問題が解決しました.
 
まずGoogleでGridViewがIEnumerableデータソースのソートをどのように実現するかを見てみましょう.
protected void GridView_Sorting(object sender, GridViewSortEventArgs e)

{

    if (e.SortDirection == SortDirection.Ascending)

    {

        switch (e.SortExpression)

        {

            case "property1":

                //IEnumber<T>.OrderBy(t => t.property1);

                break;

            case "property2":

                //IEnumber<T>.OrderBy(t => t.property2);

                break;

            default:

                break;

        }

    }

    else

    {

        switch (e.SortExpression)

        {

            case "property1":

                //IEnumber<T>.OrderByDescending(t => t.property1);

                break;

            case "property2":

                //IEnumber<T>.OrderByDescending(t => t.property2);

                break;

            default:

                break;

        }

    }

}

 
明らかにこの案は、タイプソートの属性が多くなると死んだ人を書く.
 
それからまた《Gridview LINQとObjectDataSourceによる自動ページングとソート》のこの文章を参考にして、自分で文章を読むのは注意深くなくて、最初は分からなかったで、ブロガーは返事をしてからやっとSystemに追加することができることを知った.Linq.Dynamicの引用は、IQueryable.OrderBy(string sortExpression)関数.その後、生成、実行、放出異常、具体的な異常名が忘れられ、いずれにしてもクエリーを動的に作成できません.
 
この異常を投げ出したのは,前述の著者らが,IQueryableのTはLinq to Sqlが直接生成したモデルであり,私のプロジェクトでは,このモデルTはデータベースに直接対応するデータテーブルではないからである.私のデータベースにはTabがありますDeviceInfo(デバイス情報テーブル)とTab_DeviceStatus(デバイスステータステーブル)ですが、私のプログラムコードにはデバイスの情報とデバイスの状態を格納するDeviceクラスが1つしか定義されていません.
 
引き続き検索して、この文章を見て、本人の英語が比較的にこすっているため、実は多くの説明は理解していないで、コードの部分だけを見ました.著者らは、反射構造Expressionの例をパラメータとしてIQueryableを呼び出す.OrderBy(Expression sortExpression)関数はソートを実現します.よって、反射によりIEnumerableを構築することを考える.OrderBy(Funckey)のパラメータを呼び出します.
 
まず、Funcはdelegateです.『からNETフレームワークにおける依頼書き方の進化談を開く(中)』を参考にして分かりました.NET 3.5で依頼された書き方は、最後にソートに関する解決策を得ました.
string sortExpression;

SortDirection sortDirection;

IEnumerable<Device> source;



//set value.



if (sortDirection == SortDirection.Ascending)

{

    GridView1.DataSource = source.OrderBy(item => item.GetType().GetProperty(sortExpression).GetValue(item, null));

}

else

{

    GridView1.DataSource = source.OrderByDescending(item => item.GetType().GetProperty(sortExpression).GetValue(item, null));

}

 
変ですが、実現してみました.前にたくさん言ったが、実は私がこの問題を解決する過程にすぎない.ただし、Linq to Sqlとして自動的に生成される汎用型のソートを実現するために用いることができる.以下に完全な例コードを差し上げます.
 
デバイス類:
public class Device

{

    private Tab_DeviceInfo _deviceInfo;



    /// <summary>

    /// /// </summary>

    /// <param name="deviceInfo"></param>

    internal Device(Tab_DeviceInfo deviceInfo)

    {

        _deviceInfo = deviceInfo;



        //       ,     。

    }



    #region /// <summary>

    /// /// </summary>

    public int ID

    {

        get

        {

            return _deviceInfo.DI_ID;

        }

        set

        {

            _deviceInfo.DI_ID = value;

        }

    }



    /// <summary>

    /// /// </summary>

    public string NO

    {

        get

        {

            return _deviceInfo.DI_DeviceNO;

        }

        set

        {

            _deviceInfo.DI_DeviceNO = value;

        }

    }



    #endregion

}

 
.aspxファイル:
<form id="form1" runat="server">

<div>

    <asp:GridView ID="GridViewDevice" runat="server" AllowSorting="True" OnSorting="GridViewDevice_Sorting">

        <Columns>

            <asp:BoundField DataField="ID" HeaderText="    " SortExpression="ID" />

            <asp:BoundField DataField="NO" HeaderText="    " SortExpression="NO" />

        </Columns>

    </asp:GridView>

</div>

</form>

 
.aspx.csファイル:
public partial class OrderByProperty : System.Web.UI.Page

{

    private GSMDataContext _data;



    /// <summary>

    /// /// </summary>

    public OrderByProperty()

    {

        _data = new GSMDataContext();

    }



    private void bindGridViewData()

    {

        if (!IsPostBack)

        {

            GridViewDevice.DataKeyNames = new string[] { "ID" };

        }



        string sortExpression = GridViewDevice.Attributes["sortExpression"];

        SortDirection sortDirection = GridViewDevice.Attributes["sortDirection"] == "ASC" ? SortDirection.Ascending : SortDirection.Descending;

        IEnumerable<Device> source = _data.Tab_DeviceInfos.Select(info => new Device(info));



        if (string.IsNullOrEmpty(sortExpression))

        {

            GridViewDevice.DataSource = source;

        }

        else

        {

            if (sortDirection == SortDirection.Ascending)

            {

                GridViewDevice.DataSource = source.OrderBy(item => item.GetType().GetProperty(sortExpression).GetValue(item, null));

            }

            else

            {

                GridViewDevice.DataSource = source.OrderByDescending(item => item.GetType().GetProperty(sortExpression).GetValue(item, null));

            }

        }

        GridViewDevice.DataBind();

    }



    protected void Page_Load(object sender, EventArgs e)

    {

        bindGridViewData();

    }



    protected void GridViewDevice_Sorting(object sender, GridViewSortEventArgs e)

    {

        //  sortExpression sortDirection。

        string sortExpression = e.SortExpression;

        string sortDirection = "ASC";

        if (sortExpression.Equals(GridViewDevice.Attributes["sortExpression"]) && "ASC".Equals(GridViewDevice.Attributes["sortDirection"]))

        {

            sortDirection = "DESC";

        }

        GridViewDevice.Attributes.Add("sortExpression", sortExpression);

        GridViewDevice.Attributes.Add("sortDirection", sortDirection);



        bindGridViewData();

    }

}

 
 
補足:
文章は昨日書いたもので、IEnumerablesource=data.Tab_DeviceInfos.Select(info => new Device(info));この行のコードには、昨日var source=_が使われていました.data.Tab_DeviceInfos.Select(info => new Device(info));.リリース後、ポイントダウンして運転して、異常を投げて、Systemに基づいてはいけません.Objectタイプを並べ替えます.IEnumberと直接宣言しないと、Select関数はIQueryableのインスタンスを返し、上記の異常が投げ出されます.解決策は、私のようにIEnumberableと宣言するか、sourceを先に呼び出すことができます.AsEnumerable()は、反射でそのタイプを取得し、強回転します.コードは次のとおりです.
ツールクラスcs:
public class SortUtility

{

    public static object Sort(IEnumerable source, string sortExpression, SortDirection sortDirection)

    {

        IEnumerator sourceEnumerator = source.GetEnumerator();



        if (!sourceEnumerator.MoveNext())

        {

            return null;

        }



        Type dataSourceType = source.GetType();



        Type dataItemType = typeof(object);



        if (dataSourceType.HasElementType)

        {

            dataItemType = dataSourceType.GetElementType();

        }

        else if (dataSourceType.IsGenericType)

        {

            dataItemType = dataSourceType.GetGenericArguments().FirstOrDefault();

        }

        else

        {

            if (sourceEnumerator.Current != null)

            {

                dataItemType = sourceEnumerator.Current.GetType();

            }

        }



        // We'll handle things like LINQ to SQL differently by passing the love

        // on to the provider.

        PropertyInfo sortProperty = dataItemType.GetProperty(sortExpression);



        //       ,     。

        if (sortProperty == null)

        {

            return source;

        }



        Type sorterType = typeof(SortUtility<,>).MakeGenericType(dataItemType, sortProperty.PropertyType);



        object sorterObject = Activator.CreateInstance(sorterType);



        return sorterType.GetMethod("Sort", new Type[] { dataSourceType, typeof(string), typeof(SortDirection) })

            .Invoke(sorterObject, new object[] { source, sortExpression, sortDirection });

    }

}



public class SortUtility<T, ST>

{

    public static IEnumerable<T> Sort(IEnumerable<T> source, string sortExpression, SortDirection sortDirection)

    {

        Func<T, ST> sortFunc = item => (ST)typeof(T).GetProperty(sortExpression).GetValue(item, null);



        if (sortDirection == SortDirection.Ascending)

        {

            return source.OrderBy<T, ST>(sortFunc);

        }

        else

        {

            return source.OrderByDescending<T, ST>(sortFunc);

        }

    }

}

 
.aspx.csでバインドされたデータ部分のコード:
private void bindGridViewData()

{

    if (!IsPostBack)

    {

        GridViewDevice.DataKeyNames = new string[] { "ID" };

    }



    string sortExpression = GridViewDevice.Attributes["sortExpression"];

    SortDirection sortDirection = GridViewDevice.Attributes["sortDirection"] == "ASC" ? SortDirection.Ascending : SortDirection.Descending;

    var source = _data.Tab_DeviceInfos.Select(info => new Device(info));



    if (string.IsNullOrEmpty(sortExpression))

    {

        GridViewDevice.DataSource = source;

    }

    else

    {

        /*

        if (sortDirection == SortDirection.Ascending)

        {

            GridViewDevice.DataSource = source.OrderBy(item => item.GetType().GetProperty(sortExpression).GetValue(item, null));

        }

        else

        {

            GridViewDevice.DataSource = source.OrderByDescending(item => item.GetType().GetProperty(sortExpression).GetValue(item, null));

        }

         */

        GridViewDevice.DataSource = SortUtility.Sort(source, sortExpression, sortDirection);

    }

    GridViewDevice.DataBind();

}