2010-05-20 42 views
2

在SubSonic 3.04的SimpleRepository中,似乎無法在lambda表達式中執行Contains操作。下面是一個簡單的例子:Lambda包含在SimpleRepository.Find中

SimpleRepository repo = new SimpleRepository("ConnectionString"); 

List<int> userIds = new List<int>(); 
userIds.Add(1); 
userIds.Add(3); 

List<User> users = repo.Find<User>(x => userIds.Contains(x.Id)).ToList(); 

我得到的錯誤消息:

變量 'x' 的類型 '用戶' 從範圍 '' 引用,但它沒有定義的

我在這裏錯過了什麼,或者SubSonic在lambda表達式中不支持Contains?如果不是,這將如何完成?

+0

可恥的是他們......它不喜歡搶不知道 http://blog.wekeroad.com/blog/creating-in-queries-with-linq-to -sql/ – jvenema 2010-05-20 17:24:49

回答

4

由於這些都不似乎工作...

x => guids.Contains(x.Guid) 
x => guids.Any(y => y == x.Guid) 

...我們寫了生成定製的lambda表達式生成器:

x => x.Id == {id1} OR x.Id == {id2} OR x.Id == {id3} 

這是一個簡單的場景,但演示瞭如何GetContainsId<User>(ids, repo)會發現所有用戶與匹配所提供的列表的東西的ID。

public List<T> GetContainsId<T>(List<int> ids, SimpleRepository repo) 
    where T : Record, new() // `Record` is a base class with property Id 
{ 
    ParameterExpression x = Expression.Parameter(typeof(T), "x"); 
    LambdaExpression expr; 
    if (ids.Count == 0) 
    { 
     expr = Expression.Lambda(LambdaExpression.Constant(false), x); 
    } 
    else 
    { 
     expr = Expression.Lambda(BuildEqual(x, ids.ToArray()), x); 
    } 

    return repo.Find<T>((Expression<Func<T,bool>>)expr).ToList(); 
} 

private BinaryExpression BuildEqual(ParameterExpression x, int id) 
{ 
    MemberExpression left = Expression.Property(x, "Id"); 
    ConstantExpression right = Expression.Constant(id); 
    return Expression.Equal(left, right); 
} 

private BinaryExpression BuildEqual(ParameterExpression x, int[] ids, int pos = 0) 
{ 
    int id = ids[pos]; 
    pos++; 

    if (pos == ids.Length) 
    { 
     return BuildEqual(x, id); 
    } 

    return Expression.OrElse(BuildEqual(x, ids, pos), BuildEqual(x, id)); 
} 
+0

剛剛意識到在構建Or表達式的操作順序中存在一個小錯誤。在示例中修復。 – Anton 2010-06-03 22:45:54

0

Subsonic可能無法轉換userIds.Contains,因爲它無法將該列表翻譯成它可以在SQL數據庫上執行的內容。你可能不得不求助於到explictely定義或條件:

repo.Find<User>(x => x.Id == 1 || x.Id == 3).ToList(); 
0

我很確定這將工作,如果您使用IEnumerable而不是List。所以下面應該工作:

SimpleRepository repo = new SimpleRepository("ConnectionString"); 

IEnumerable<int> userIds = new List<int>(); 
userIds.Add(1); 
userIds.Add(3); 

List<User> users = repo.Find<User>(x => userIds.Contains(x.Id)).ToList(); 
+0

不適用於我,除非我的代碼有其他錯誤。你確定? (另外,Subsonic 3.1是怎麼來的?) – Anton 2010-05-20 20:11:28

+0

嗯,試着做userIds.Contains(x.Id.ToString())) - 3.1暫時擱置,我將在這個週末發佈郵件列表更新。 – 2010-05-22 10:19:26