Click here to Skip to main content
15,889,462 members
Articles / Web Development / ASP.NET
Article

Generic sorting of customer objects for ObjectDataSource (ASP.NET)

Rate me:
Please Sign up or sign in to vote.
3.77/5 (7 votes)
23 Oct 2008GPL3 28K   30   2
Generic sorting of customer objects for ObjectDataSource in ASP.NET.

Introduction

The class PropertyComparer provides the possibility for data-access-components to enable sorting for customer objects when using an ObjectDataSource.

Background

ASP.NET 2.0 includes the controls GridView and ObjectDataSource. You can define which methods of your data-access-component is used by the ObjectDataSource. If the Select method returns a DataSet or a DataTable, you can use paging and sorting for the GridView out of the box.

If you want to work with collections of business-objects instead of DataSet/DataTable, you have to implement the sorting yourself. I wrote a generic comparer for use with all my business-objects.

Using the code

Use a GridView where you define the DataSourceId, and enable sorting:

ASP.NET
<asp:GridView     ID="exampleGridView" runat="server" 
        DataSourceID="exampleDataSource" 
        AllowSorting="True" ... >

Define the ObjectDataSource:

ASP.NET
<asp:ObjectDataSource     ID="exampleDataSource" runat="server" 
            TypeName="ExampleDataAccessComponent" 
            SelectMethod="Select" 
            SortParameterName="orderBy" ... >

Write your data-access-component implementing the Select method:

C#
[DataObject()]
public sealed class ActivityDac
{
    private string myConnectionString;
    private DbProviderFactory myFactory;


    public ActivityDac()
    {
        ConnectionStringSettings cs = 
           ConfigurationManager.ConnectionStrings[" ... "];
        myFactory = DbProviderFactories.GetFactory(cs.ProviderName);
        myConnectionString = cs.ConnectionString;
    }


    [DataObjectMethod(DataObjectMethodType.Select, true)]
    public Activity[] Select(string orderBy)
    {
        List<BusinessClass> list = new List<BusinessClass>();
        using (DbConnection con = myFactory.CreateConnection())
        {
            con.ConnectionString = myConnectionString;
            using (DbCommand cmd = myFactory.CreateCommand())
            {
                cmd.Connection = con;
                cmd.CommandText = " ... ";

                DbParameter p = myFactory.CreateParameter();
                ...
                cmd.Parameters.Add(p);

                con.Open();
                DbDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleResult);

                while (reader.Read())
                {
                    BusinessClass o = new BusinessClass(reader.GetInt32(0));
                    ..
                    list.Add(o);
                }
            }
        }

        if (!String.IsNullOrEmpty(orderBy))
        {
            PropertyComparer<BusinessClass> comparer = 
              new PropertyComparer<BusinessClass>(orderBy);
            list.Sort(comparer);
        }

        return list.ToArray();
    }
}

Here is the code for the PropertyComparer:

C#
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Collections;

namespace Example
{
    public class PropertyComparer<T> : IComparer<T>
    {
        private enum SortType
        {
            Descending = -1,
            Ascending = 1
        }


        private SortType mySortDirecton;
        private string mySortPropertyName;


        public PropertyComparer(string sortString)
        {
            if (sortString == null)
                throw new ArgumentNullException("sortString");
            if (sortString.Length == 0)
                throw new ArgumentOutOfRangeException("sortString");

            if (sortString.ToLower().EndsWith(" desc"))
            {
                mySortPropertyName = sortString.Substring(0, sortString.Length - 5);
                mySortDirecton = SortType.Descending;
            }
            else
            {
                if (sortString.ToLower().EndsWith(" asc"))
                    mySortPropertyName = sortString.Substring(0, sortString.Length - 4);
                else
                    this.mySortPropertyName = sortString;

                this.mySortDirecton = SortType.Ascending;
            }
        }


        #region IComparer<T> Members

        public int Compare(T x, T y)
        {
            if ((x == null) && (y == null))
                return 0;
            if (x == null)
                return -(int)mySortDirecton;
            if (y == null)
                return (int)mySortDirecton;

            PropertyInfo p = x.GetType().GetProperty(mySortPropertyName);
            if (p == null)
                throw new ApplicationException();

            object vX = p.GetValue(x, null);
            object vY = p.GetValue(y, null);

            if ((vX == null) && (vY == null))
                return 0;
            if (vX == null)
                return -(int)mySortDirecton;
            if (vY == null)
                return (int)mySortDirecton;

            return (int)mySortDirecton * Comparer.DefaultInvariant.Compare(vX, vY);
        }

        #endregion
    }
}

History

  • Oct. 24, 2008: 9:23 - Corrected typo.

    License

    This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


    Written By
    Software Developer
    Austria Austria
    This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

    Comments and Discussions

     
    GeneralSorting should be made on all objects - Pin
    toebens28-Oct-08 23:04
    toebens28-Oct-08 23:04 
    GeneralRe: Sorting should be made on all objects - Pin
    Andreas Kranister29-Oct-08 0:08
    Andreas Kranister29-Oct-08 0:08 
    Hi tobias421,

    of course there are different ways to achieve a goal. They all have advantages and disadvantages. I do not want to discuss these philosphical questions, the best solution depends on the project goal.

    The solution I provided here is for the case when you do not page the data by sql server statement but on the webserver like the objectdatasource does out of the box. You select all the data, sort it in the data-access-layer and give this sorted data to the objectdatasource where it gets paged.

    This behaviour has of course advantages and disadvantages:
    Advantages:
    1. You can sort the data on properties which are not stored on the database server (e.g. computed properties). Of course you can say that it is possible to use computed columns in the database to sort for them but that means you have to implement business logic in a layer where it shouldn't be and it has to fit perfectly to the way how you calculate the value in the business layer, that's not a good solution.
    2. Transparent behaviour independent from the datasource, even from provider
    3. Transparent behaviour independent from the implementation of the businessobject

    Disadvantages:
    1. Ineffective for large datatables on the database server: The whole data is selected each time you sort or change the page, especially when the database server and the webserver don't have a fast connection. This argument may fit in some cases, but I am sure it is a question of architecture and completly dependent on the project.

    Greetings, Andreas

    General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

    Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.