2009-06-04 80 views
5

我正在通過將Linq轉換爲編譯查詢來加速Linq到SQL查詢的過程,並且遇到了轉換非常簡單的語句的問題。Linq使用包含編譯查詢(與SQL IN語句相似)

我想編譯使用下面的參數來從數據庫中獲取有效的員工提供一個簡單的聲明:

TestParams myParams = new TestParams 
{ 
    ValidEmps = new int[] { 1, 2, 3 } 
}; 

這裏是工作的查詢:

IQueryable<Employees> MySelectedEmps = 
    from emps in db.Employees 
    where myParams.ValidEmps.Contains(emps.EmployeeID) 
    select emps; 

這是我在編譯的嘗試它:

private static Func<MyDataContext, TestParams, IQueryable<Employee>> myCompiledQuery = 
    CompiledQuery.Compile((MyDataContext db, TestParams myParams) => 
     from emps in db.Employees 
     where myParams.ValidEmps.Contains(emps.EmployeeID) 
     select emps); 

這個聲明與編譯和構建,但是當我運行它時,我收到以下運行時錯誤:

Comparison operators not supported for type 'System.Int32[]'

我也嘗試傳遞列表和IEnumerable具有相同的錯誤消息。

我也嘗試用.Any(valemp => valemp == emps.EmployeeID)語句替換.Contains語句,但我仍然得到相同的錯誤。

是否有可能使用SQL「IN」語句的等效語句進行編譯?我究竟做錯了什麼?

+1

http://stackoverflow.com/questions/813256/compiled-queries-and-parameters-cannot-be-sequences – 2009-06-04 21:33:31

+0

感謝您的鏈接。這令人失望的消息,我不認爲任何人有一個可行的解決方法? – 2009-06-04 21:37:12

+0

嘗試一個存儲過程,因爲我建議下面... – 2009-06-04 21:58:52

回答

5

調用存儲過程,並傳入值的CVS列表,使用這種方法:

之前,你用我的功能,你需要建立一個「助手」表,你只需要做這一個每個數據庫的時間:

CREATE TABLE Numbers 
(Number int NOT NULL, 
    CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 
DECLARE @x int 
SET @x=0 
WHILE @x<8000 
BEGIN 
    SET @[email protected]+1 
    INSERT INTO Numbers VALUES (@x) 
END 

使用此功能來分割你的字符串,它不循環,是非常快:

CREATE FUNCTION [dbo].[FN_ListToTable] 
(
    @SplitOn    char(1)    --REQUIRED, the character to split the @List string on 
    ,@List     varchar(8000)  --REQUIRED, the list to split apart 
) 
RETURNS 
@ParsedList table 
(
    ListValue varchar(500) 
) 
AS 
BEGIN 

/** 
Takes the given @List string and splits it apart based on the given @SplitOn character. 
A table is returned, one row per split item, with a column name "ListValue". 
This function workes for fixed or variable lenght items. 
Empty and null items will not be included in the results set. 


Returns a table, one row per item in the list, with a column name "ListValue" 

EXAMPLE: 
---------- 
SELECT * FROM dbo.FN_ListToTable(',','1,12,123,1234,54321,6,A,*,|||,,,,B') 

    returns: 
     ListValue 
     ----------- 
     1 
     12 
     123 
     1234 
     54321 
     6 
     A 
     * 
     ||| 
     B 

     (10 row(s) affected) 

**/ 



---------------- 
--SINGLE QUERY-- --this will not return empty rows 
---------------- 
INSERT INTO @ParsedList 
     (ListValue) 
    SELECT 
     ListValue 
     FROM (SELECT 
        LTRIM(RTRIM(SUBSTRING(List2, number+1, CHARINDEX(@SplitOn, List2, number+1)-number - 1))) AS ListValue 
        FROM (
          SELECT @SplitOn + @List + @SplitOn AS List2 
         ) AS dt 
         INNER JOIN Numbers n ON n.Number < LEN(dt.List2) 
        WHERE SUBSTRING(List2, number, 1) = @SplitOn 
      ) dt2 
     WHERE ListValue IS NOT NULL AND ListValue!='' 



RETURN 

END --Function FN_ListToTable 

您可以使用此功能作爲一個表的連接:

SELECT 
    Col1, COl2, Col3... 
    FROM YourTable 
     INNER JOIN FN_ListToTable(',',@YourString) s ON YourTable.ID = s.ListValue 

所以對LINQ,創建一個存儲過程:

CREATE PROCEDURE YourProcedure (

@param1 int 
,@param2 varchar(8000) --csv list is here 

) 作爲

SELECT 
    Col1, COl2, Col3... 
    FROM YourTable 
     INNER JOIN FN_ListToTable(',',@param2 ) s ON YourTable.ID = s.ListValue 
    WHERE [email protected] 

0

不會在

CompiledQuery.Compile 

功能必須

CompiledQuery.Compile<MyDataContext, TestParams, IQueryable<Employee>> 

呢?

你有沒有嘗試使用Int32擴展(我asume EmployeeID是一個Int32)與In函數?

public static class Int32Extensions 
{ 
    public static bool In(this int input, List<int> list) 
    { 
     if (list == null || list.Count == 0) return false; 
     return list.Contains(input); 
    } 
} 

private static Func<MyDataContext, TestParams, IQueryable<Employee>> myCompiledQuery = 
    CompiledQuery.Compile<MyDataContext, TestParams, IQueryable<Employee>>((MyDataContext db, TestParams myParams) => 
    from emps in db.Employees 
    where emps.EmployeeID.In(myParams.ValidEmps) 
    select emps); 

Grtz,

0

我碰到了同樣的問題一次,我敢肯定(我得研究),我是能夠用一種方法創建一個類來解決問題在它上面返回一個布爾值,然後我會從數據行傳遞該項並返回true/false。