2012-05-24 80 views
0

我有一個linq查詢,它沒有按照我想要的方式排序。linq orderby問題(按自定義規則對字符串進行排序)

查詢:

return (from obj in context.table_orders 
    orderby obj.order_no 
    select obj.order_no.ToString() + '-' + obj.order_description).ToList<string>(); 

會發生什麼事是,我的記錄是alphabeticaly有序的,是有一個LINQ關鍵字,我可以使用,所以我的記錄是正確排序(所以訂購訂購100前30來)?

我想結果是一個字符串列表,因爲這是用來填充組合框。

另外一些DB中的'order_no'就像'2.10'和'9.1.1'。

+0

所以'order_no'實際上並不是一個數字? –

+0

沒有數據庫它是一個varchar(例如:'10。1') –

回答

0

因爲沒有人想出了一個自定義排序依據功能翻譯成SQL,我去了IComparer的功能,像這樣:

public class OrderComparer<T> : IComparer<string> 
    { 
     #region IComparer<string> Members 

     public int Compare(string x, string y) 
     { 
      return GetOrderableValue(x.Split('-').First()).CompareTo(GetOrderableValue(y.Split('-').First())); 
     } 
     #endregion 

     private int GetOrderableValue(string value) 
     { 
      string[] splitValue = value.Split('.'); 
      int orderableValue = 0; 
      if (splitValue.Length.Equals(1)) 
       orderableValue = int.Parse(splitValue[0]) * 1000; 
      else if (splitValue.Length.Equals(2)) 
       orderableValue = int.Parse(splitValue[0]) * 1000 + int.Parse(splitValue[1]) * 100; 
      else if (splitValue.Length.Equals(3)) 
       orderableValue = int.Parse(splitValue[0]) * 1000 + int.Parse(splitValue[1]) * 100 + int.Parse(splitValue[2]) * 10; 
      else 
       orderableValue = int.Parse(splitValue[0]) * 1000 + int.Parse(splitValue[1]) * 100 + int.Parse(splitValue[2]) * 10 + int.Parse(splitValue[3]); 

      return orderableValue; 
     } 
    } 

值有一個最大的4個層次。 任何人都有推薦?

+0

看到我的答案爲比較器的提議的邏輯 - 你不需要這個if/else塊,但你可以通過序列foreach –

+0

也許太舊,但我會建議像 int val = 0; value.Split('。')。toList()。ForEach(v => val + = v); –

3

會發生什麼事是,我的記錄是alphabeticaly有序的,是有一個LINQ關鍵字,我可以使用,所以我的記錄 正確排序(所以下令#30到來之前的訂單號100)?

如果我會得到一箇中心每次有人問這個我會很有錢。

是的,有 - 簡單的答案:命令一個數字不是一個字符串。

所以爲了#30到來之前的訂單號100)

但是#30來AFTER#100,理由很簡單,他們是按字母順序排序becase的這些值是字符串。

解析字符串,將數字轉換爲 - well - 一個數字,並按順序排列。

曾經有一個想法,order_no應該是一個沒有固定長度的字符串(如00030)應該 - 好 - ;)獲得關於數據庫建模的基礎教育。我真的很喜歡像發票號碼等字符串(它們不是數字),但將它們保留在(a)明確的模式和(b)校驗和(以便容易捕捉數據輸入錯誤)應該是基本的;)

這是您在初級人員定義數據庫和數據模型時沒有考慮後果的問題。

你在爲一些痛苦 - 解析字符串,按解析結果排序。

+0

實際上它不是訂單表,數字更像是一個帶點而不是逗號的識別標籤。 –

0

如果obj.order_no是一個字符串,然後將其轉換爲數字進行排序

orderby Int32.Parse(obj.order_no) 

orderby Decimal.Parse(obj.order_no) 

原因這隻有當字符串表示有效數字。


如果order_no不是有效的數字(例如,"17.7-8A"),然後編寫格式它含有右對齊的數字,如"00017.007-0008A"和排序使用此功能

orderby FormatOrderNo(obj.order_no) 
功能

UPDATE

既然你與EF工作,你不能調用這個函數在查詢的EF部分。轉換的EF-結果的IEnumerable<T>並使用基於你在說什麼

return (from obj in context.table_orders select ...) 
    .AsEnumerable() 
    .OrderBy(obj => FormatOrderNo(obj.order_no)) 
    .ToList(); 
+0

我不確定,但我不認爲這可以在linq-to-sql上下文 –

+0

nope不起作用。 (Method'System.Decimal Parse(System.String)'沒有支持到SQL的轉換。)但是好的嘗試:我正在尋找類似的東西。 –

+0

我在考慮LINQ到對象。然後排序它'返回(從obj in context.table_orders選擇...)。AsEnumerable()。OrderBy(obj => FormatOrderNo(obj.order_no))。ToList();' –

0

LINQ到對象進行排序 - 這些數字是不是真的數字,而是自定義序列標識符(即你甚至不知道你得到什麼水平的深度)我會建議實現一個自定義比較器。

如果你這樣做,你可以定義你exaclty想要的東西 - 那就是我相信這些方針的東西:

  • 分割字符串上.
  • 序列比較直至幷包括了陣列。較短序列
  • 如果有一個較短的序列,並通過現在有一條領帶的長度,之前的時間越長(2.1.1之前即2.1
  • 挑較短如果兩個序列具有相同的長度,在比較結束時,您應該知道哪一個'更大'
  • 已解決。

如果您需要IComparer執行下面的例子啓發:
http://zootfroot.blogspot.co.uk/2009/09/natural-sort-compare-with-linq-orderby.html

0

如果可能的話我會請更改數據類型或如適用其添加爲另一個firld。 如果這是一個禁忌,你可以看看其他人在這個問題中提到的解決方案,但要小心 - 如果你從他們身上拉取所有東西,但是習慣它,最終會給你提供.ToList()一個痛苦的世界。從長遠來看,你不想得到任何東西,要麼使用Where或頂級標準。

其他的解決方案很好,但爲了完成任務我的口味變得複雜。

你可以直接通過LinqToSql拍攝sql。 http://msdn.microsoft.com/en-us/library/bb399403.aspx

在sql中,您可以自由轉換和排序,但是你喜歡。有人認爲這是一個好主意,有些人會告訴你它是不好的。你失去了強大的打字和獲得表現。你將不得不知道你爲什麼採取這種決定,這是最重要的事情。