none
use CompareOptions.Ordinal in DataView.Sort RRS feed

  • Question

  • Is there any way to force a DataView.Sort on a string column to use CompareOptions.Ordinal?  As far as I can see, CompareOptions is None when DataTable.CaseSensitive = true, or IgnoreCase | IgnoreKanaType | IgnoreWidth when DataTable.CaseSensitive = false.  Is there any way to specify CompareOptions.Ordinal other than using reflection to set the private DataTable._compareFlags field?
    tushka
    Wednesday, December 16, 2009 4:23 PM

Answers

  • Hello tushka,

     

    Yes, you are correct.  We need to populate the user-defined columns, so it will bring more additional operations.  For the Reflection method, it would be more efficient.  Also as far as I know, using Reflection in this case also works in new version of .NET Framework.   Actually, for newer versions of .NET Framework, we can use LINQ to DataSet as a good choice.  J  

     

     

    Best Regards,
    Lingzhi Sun

    MSDN Subscriber Support in Forum

    If you have any feedback on our support, please contact msdnmg@microsoft.com

     


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Tuesday, December 29, 2009 4:51 AM
    Moderator

All replies

  • Hi Tushka,
    your question is vague, Can you please elaborate?

    The code below get you the Ordinal of the column

    myDataTable.CreateDataReader.GetOrdinal("ColumnName")

    John
    • Edited by Codernater Thursday, December 17, 2009 12:50 AM v
    Thursday, December 17, 2009 12:50 AM
  • Not that kind of ordinal.  There's 3 ways to sort strings, the simplest one is ordinal sort where it simply compares character by character numerically by their unicode value.  The others are word sort which assign weights to each character in the string, and string sort (not sure how that works).  In a word sort punctuation characters get less weight so if you have FOO and F.O.O. they will be close together in a word sort but not in an ordinal sort.  API calls such as String.Compare allow you to specify which sort to use, but DataView.Sort doesn't
    tushka
    Friday, December 18, 2009 1:39 AM
  • Hello tushka,

     

    As you said, the _compareFlags of the DataTable is set to None when CaseSensitive is true and set to IgnoreCase | IngoreKanaType | IgnoreWidth when CaseSensitive is false (default value ).   We can verify it by checking the implementation of the DataTable class via .NET Reflector:

    ==================================================================================================

        public DataTable()

        {

            this.tableName = "";

            this.tablePrefix = "";

            this.fNestedInDataset = true;

            this._compareFlags = CompareOptions.IgnoreWidth | CompareOptions.IgnoreKanaType | CompareOptions.IgnoreCase;

            ……

    }

     

        internal bool SetCaseSensitiveValue(bool isCaseSensitive, bool userSet, bool resetIndexes)

        {

            if (!userSet && (this._caseSensitiveUserSet || (this._caseSensitive == isCaseSensitive)))

            {

                return false;

            }

            this._caseSensitive = isCaseSensitive;

            if (isCaseSensitive)

            {

                this._compareFlags = CompareOptions.None;

            }

            else

            {

                this._compareFlags = CompareOptions.IgnoreWidth | CompareOptions.IgnoreKanaType | CompareOptions.IgnoreCase;

            }

            …….

        }

    ==================================================================================================

     

    From the DataTable, I don’t find any methods for us to manually set the CompareOptions, it seems that we can only use the Reflection.

     

     

    Besides, how about using LINQ to DataSet, like the following query?

    ==================================================================================================

    var query = table.AsEnumerable().OrderBy(r => r.Field<string>("ColumnName"), StringComparer.Ordinal);
    ==================================================================================================

     

     

    If you have any questions, please feel free to let me know.

     

    Have a nice weekend!

     

     

    Best Regards,
    Lingzhi Sun

    MSDN Subscriber Support in Forum

    If you have any feedback on our support, please contact msdnmg@microsoft.com


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Friday, December 18, 2009 6:03 AM
    Moderator
  • Thanks Lingzhi, The LINQ option would be a good alternative for .Net 3.5, unfortunately I need to do this with .Net 2.0.
    tushka
    Saturday, December 19, 2009 4:27 PM
  • Hello tushka,

     

    I will consult the product team to see whether we have other workaround on .NET 2.0 and get back to you as soon as I can. 

     

    Have a nice day!

     

    Best Regards,
    Lingzhi Sun

    MSDN Subscriber Support in Forum

    If you have any feedback on our support, please contact msdnmg@microsoft.com


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Monday, December 21, 2009 4:24 AM
    Moderator
  • Hello tushka,

     

    Indeed, it seems that the DataView.Sort property is limited to list of columns with either ASC or DESC order. 

     

    Thanks to the product team’s help, I got two workarounds for this question:

     

    1.      Create an additional (integer) column, swap their values each sort operation and control sorting by using this column.

    2.      A much better alternative would be creating an additional column with custom type that implements IComparable and sort this column: DataView will use object.CompareTo method to perform sorting:

     

    Here is an example:

    ===============================================================================================

      class MyColumnComparer : IComparable, IComparable<MyColumnComparer>

            {

                string CompareValue;

     

                public MyColumnComparer(string value)

                {

                    CompareValue = value;

                }

     

                public int CompareTo(object obj)

                {

                    MyColumnComparer other = obj as MyColumnComparer;

                    if (other == null)

                        return 1;

                    else

                        return string.Compare(CompareValue, other.CompareValue, StringComparison.OrdinalIgnoreCase);

                }

            }

     

            DataTable table = new DataTable();

            table.Columns.Add("Comparer", typeof(MyColumnComparer));

            DataView dView = new DataView(table);

            dView.Sort = "Comparer ASC";

    ===============================================================================================

     

    Are these two workarounds helpful on your case?   Feel free to tell me if you have any questions.

     

    Merry Christmas & Happy New Year!

     

    Best Regards,
    Lingzhi Sun

    MSDN Subscriber Support in Forum

    If you have any feedback on our support, please contact msdnmg@microsoft.com


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Thursday, December 24, 2009 3:27 AM
    Moderator
  • Hi Lingzhi, Merry Xmas and happy new year to you as well. 

    I'm not sure I understand the first option of creating an additional integer column.

    The second option creating an additional column of a user-defined type that implements IComparable seems workable, maybe a bit inefficient.  If I'm not mistaken, your example omits the step of populating the user-defined column which requires an additional iteration thru the table ie:

    table.Columns.Add("Comparer", typeof(MyColumnComparer));
    foreach (DataRow row in table) row["Comparer"] = new MyColumnComparer((string)row["OriginalStringValue"]);

    If that's the case, then I guess it's a trade-off, setting the internal _compareFlags field thru reflection wouldn't require the additional iteration, and so is more efficient, but isn't clean and may not work for future releases.
    tushka
    Tuesday, December 29, 2009 1:49 AM
  • Hello tushka,

     

    Yes, you are correct.  We need to populate the user-defined columns, so it will bring more additional operations.  For the Reflection method, it would be more efficient.  Also as far as I know, using Reflection in this case also works in new version of .NET Framework.   Actually, for newer versions of .NET Framework, we can use LINQ to DataSet as a good choice.  J  

     

     

    Best Regards,
    Lingzhi Sun

    MSDN Subscriber Support in Forum

    If you have any feedback on our support, please contact msdnmg@microsoft.com

     


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Tuesday, December 29, 2009 4:51 AM
    Moderator