ADO.Net Entity Framework : (八) 查詢時使用 ”IN” 的方式

ADO.Net Entity Framework : (八) 查詢時使用 ”IN” 的方式

當我們有這需求要查詢類似以下SQL語法時

select * from [user] where user_name in 'david','andy'

發現 Linq to Entity 並沒有提供類似 in  的語法,因此突發奇想,
改用另一個方式查詢如下

           ////範例一  
            using (TestEntities te = new TestEntities())
            {
                string[] names = new string[] { "david", "andy" };

                var users = from a in te.User
                            where names.Contains(a.User_name)
                            select a;

                GridView1.DataSource = users;
                GridView1.DataBind();
            }

結果發生錯誤 = =

LINQ to Entities 無法辨識方法 'Boolean Contains[String](System.Collections.Generic.IEnumerable`1[System.String], System.String)' 方法,而且這個方法無法轉譯成存放區運算式。

 

好吧,只好再嘗試其他方法,
改用 Query Builder Method

           ////範例二  
            using (TestEntities te = new TestEntities())
            {               
                var users = te.User.Where("it.user_name in {'david','andy'}");

                GridView1.DataSource = users;
                GridView1.DataBind();
            }

這次順利成功囉,
但是又不太甘心,因為少了intellsence 也無法在設計階段除錯

在介紹另一種方式,
我參考網路上找到的方法,建立了一個 ContainsExpression Method, 

    /// <summary>
    /// 讓 EF 支援類似 SQL "IN" 的語法   ContainsExpression
    /// </summary>   
    public static Expression<Func<TElement, bool>> ContainsExpression<TElement, TValue>(
            Expression<Func<TElement, TValue>> valueSelector, IEnumerable<TValue> values)
    {
        if (null == valueSelector)
        {
            throw new ArgumentNullException("valueSelector");
        }

        if (null == values)
        {
            throw new ArgumentNullException("values");
        }

        ParameterExpression p = valueSelector.Parameters.Single();
       
        if (!values.Any())
        {
            return e => false;
        }

        var equals = values.Select(value => (Expression)Expression.Equal(valueSelector.Body, Expression.Constant(value, typeof(TValue))));
        var body = equals.Aggregate<Expression>((accumulate, equal) => Expression.Or(accumulate, equal));
        return Expression.Lambda<Func<TElement, bool>>(body, p);
    }
}

然後使用剛剛建立的 ContainsExpression Method 進行查詢, 

           ////範例三  
            using (TestEntities te = new TestEntities())
            {
                string[] names = new string[] { "david", "andy" };

                var users = te.User.Where(ContainsExpression<User, string>(a => a.User_name, names));
                               
                GridView1.DataSource = users;
                GridView1.DataBind();
            }

可以順利執行成功唷,
我們來看看實際執行時候的SQL語法長甚麼樣子

SELECT 1 AS [C1], [Extent1].[User_id] AS [User_id]
, [Extent1].[User_name] AS [User_name]
, [Extent1].[User_email] AS [User_email]
, [Extent1].[User_userdepartmentid] AS [User_userdepartmentid] 
FROM [dbo].[User] AS [Extent1] 
WHERE (N'david' = [Extent1].[User_name]) OR (N'andy' = [Extent1].[User_name]) 

這樣的好處是 會有intellsence,但是缺點是閱讀起來比較不直覺,加上執行時的SQL語法其實是用 OR  OR  OR 去組合起來的,
感覺效率上就沒有範例二 直接使用 Query Builder Method 來的好,
不過給大家參考一下囉




 


 

  • 如果您覺得這篇文章有幫助,請您幫忙推薦一下或按上方的""給予支持,非常感激
  • 歡迎轉載,但請註明出處
  • 文章內容多是自己找資料學習到的心得,如有不詳盡或錯誤的地方,請多多指教,謝謝