2014-01-14 58 views
1

我試圖在Linq中按周分組。我創建的helper方法來定義我想通過組一週,但在運行代碼時,我得到的錯誤信息:{「法‘的Int32 GetWeekNumber(System.DateTime的)’有沒有支持轉換爲SQL」}方法在Linq中的SQL中沒有支持的翻譯

System.SystemException {} System.NotSupportedException

我的Linq查詢:

var data = from trans in _dbc.MyStuff 
     where 
      SqlMethods.Like(trans.SEGMENT2, "00601") && SqlMethods.Like(trans.SEGMENT4, "%") 
      && 
      trans.CREATION_DATE >= new DateTime(2013, 01, 01) && 
      trans.CREATION_DATE <= new DateTime(2013, 12, 31) 
     group trans by new 
     { 
      DateYear = (int?)trans.CREATION_DATE.Value.Year, 
      DateMonth = (int?)trans.CREATION_DATE.Value.Month, 
      DateWeek = (int?)WeekStuff.GetWeekNumber(trans.CREATION_DATE.Value) 
     } 
      into g 
      orderby 
       g.Key.DateYear, 
       g.Key.DateMonth, 
       g.Key.DateWeek 
      select new 
      { 
       DateYear = g.Key.DateYear ?? 0, 
       DateMonth = g.Key.DateMonth ?? 0, 
       DateWeek = g.Key.DateWeek ?? 0, 
       Value = g.Sum(p => p.BASE_TRANSACTION_VALUE) ?? 0, 
       Count = g.Sum(p => p.PRIMARY_QUANTITY) ?? 0, 
       DateCreated = g.Min(p => p.CREATION_DATE) ?? DateTime.Now, 
       Department = g.Min(p => p.SEGMENT2) 
      }; 

我的helper方法:

public static int GetWeekNumber(DateTime date) 
    { 
     if (DateTimeFormatInfo.CurrentInfo != null) 
     { 
      Calendar cal = DateTimeFormatInfo.CurrentInfo.Calendar; 
      return cal.GetWeekOfYear(date, CalendarWeekRule.FirstDay, DayOfWeek.Monday); 
     } 
     return 0; 
    } 

基本上我想要做的就是每週還要分組,如何使用helper方法進行分組(如果我實際上需要一個輔助方法來完成此操作)?

+3

你不能在Linq中使用你的方法。您需要以某種方式將其翻譯爲SQL代碼,然後使用它 –

+2

如果您要直接編寫SQL代碼,那麼您如何在SQL中完成這項工作?如果你能弄清楚如何做到這一點,那麼就考慮試着找到一種讓LINQ來編寫代碼的方法。如果你不能,那麼LINQ可能不能。 – Servy

+0

謝謝你的評論傢伙。我實際上(通過幫助)管理編寫按幾周分組的sql腳本。然而,我很難將其轉換爲Linq(但在StackOverflow中這將是一個不同的問題)。再次感謝。 – gardarvalur

回答

1

步驟1.創建SQL中的函數,它所需的計算(注意,這取決於@@DATEFIRST設置SQL服務器上:

CREATE FUNCTION [dbo].[GetWeek](@dt datetime) 
RETURNS int 
BEGIN 
    RETURN DATEPART(wk, @dt) 
END 

步驟2:在您的數據上下文類,添加功能確實同上你的助手,但被標記爲與System.Data.Linq.Mapping.FunctionAttribute屬性:

[Function(Name="dbo.GetWeek", IsComposable=true)] 
public int GetWeekNumber([Parameter(Name="@dt", DbType="datetime")]DateTime date) 
{ 
    Calendar cal = DateTimeFormatInfo.CurrentInfo.Calendar; 
    return cal.GetWeekOfYear(date, CalendarWeekRule.FirstDay, DayOfWeek.Monday); 
} 

IsComposable=true表明它可以作爲其他查詢的部分(即它是一個函數,而不是一個存儲過程)

第3步:現在改變您的查詢中使用dbc.GetWeekNumber,而不是WeekStuff.GetWeekNumber

或者,你可以定義上面的方法爲:

[Function(Name="dbo.GetWeek", IsComposable=true)] 
public int GetWeekNumber([Parameter(Name="@dt", DbType="datetime")]DateTime date) 
{ 
    return (int)ExecuteMethodCall(this, (MethodInfo)MethodInfo.GetCurrentMethod(), date).ReturnValue; 
} 

這樣一來,即使在所謂的查詢之外,它會打到數據庫,而不是在.NET代碼計算它。這比較慢(如果沒有它,我們可以計算出一個數據庫),但是它的優點是可以保持命中數據庫的代碼與不符合代碼的第一天的概念一致。

+0

哇!這實際上是訣竅。我沒有意識到使用sql函數,linq可以像這樣手拉手。我將需要檢查datefirst的sql服務器的設置,但這是一個很好的答案,適用於我。謝謝:) – gardarvalur

+0

正如Linq2SQL已經知道如何映射一些。.NET方法轉換爲SQL,就像'[Table]'屬性告訴它如何將類映射到表一樣,所以'[Function]'屬性告訴它如何將新方法映射到SQL。你也可以將它與存儲過程一起使用,但是你需要'IsComposable = false',並且你更加限制你如何使用它們(就像使用存儲過程而不是函數在SQL本身中更加有限一樣)。 –

+1

順便提一句,如果你有一個表值函數,而不是標量,將其定義爲返回'IQueryable ',你可以做同樣的事情。 –

2

LINQ試圖您的代碼轉換爲SQL,並在服務器上運行它。您的自定義方法無法轉換爲SQL,這很正常。您可能需要首先填充LINQ查詢的結果,然後再使用LINQ to對象進行分組。

+0

是的,你可能是對的。我可能需要用兩個獨立的對象來做到這一點。無論如何,這裏值得一查。謝謝:) – gardarvalur