Linq表达式选择字段

时间:2011-01-12 03:24:47

标签: c# linq linq-to-sql

我有一个非常具体的LINQ查询。我想检查表中是否存在随机生成的密钥。

标准查询可以定义为Select * from Products where SaleId == 'XXXXXXX'。 在此查询中,XXXXXX由随机字符生成器生成(还提供了长度)。我创建了以下LINQ扩展:

public static string GetUniqueId<T, TProperty>(this IEnumerable<T> source, int length, Func<T, TProperty> idProperty)
{
    bool isUnique = false;
    string uniqueId = String.Empty;
    while (!isUnique)
    {
        uniqueId = PasswordGenerator.GenerateNoSpecialCharacters(length);
        if (!String.IsNullOrEmpty(uniqueId))
        {
            isUnique = source.AsQueryable().SingleOrDefault(i => idProperty(i).Equals(uniqueId)) == null;
        }
    }
    return uniqueId;
}

但是,我注意到此方法首先从表中选择作为源传递的所有记录,然后运行Where子句。这种行为显然非常耗时。所以基本上它SELECT * FROM Products然后运行SingleOrDefault

我有什么方法可以直接运行查询,以便它从产品中选择* * WHERE Id ='XXXXXXX'

以下是我如何称呼它的一个例子:

string id = c.L2SOnlineCountMasters.GetUniqueId(9, x => x.MID);

在这种情况下,L2SOnlineCountMasters是数据库中的表,c是DataContext实例。

希望得到这个答案!

Cheerz, 阿努普

3 个答案:

答案 0 :(得分:1)

LINQ-to-SQL引擎无法知道Func<T, TProperty>的作用。

您需要接受Expression<Func<T, TProperty>>,然后将表达式拼接成一个调用.Equals的表达式。
代码看起来像

Expression.Lambda<Func<T, TProperty>>(
    Expression.Call(idProperty.Body, "Equals", new Type[0], 
                    Expresion.Constant(uniqueId)),
    idProperty.Parameters
)

此外,您应该更改方法以采用IQueryable<T>

答案 1 :(得分:1)

阅读完这两条评论之后,我意识到应该使用IQueryable。 但是,Expression Call中的“Equals”不起作用,因为它会引发以下错误: “类型'System.String'上的多个方法'Equals'与提供的参数兼容。”因此我按如下方式修改了代码:

public static string GetUniqueId<T, TProperty>(this IQueryable<T> source, int length, Expression<Func<T, TProperty>> idProperty)
    {
        bool isUnique = false;
        string uniqueId = String.Empty;
        while (!isUnique)
        {
            uniqueId = PasswordGenerator.GenerateNoSpecialCharacters(length);
            if (!String.IsNullOrEmpty(uniqueId))
            {
                var expr = Expression.Lambda<Func<T, bool>>(
                    Expression.Call(idProperty.Body, typeof(string).GetMethod("Equals", new[] { typeof(string) }), Expression.Constant(uniqueId)), idProperty.Parameters);
                isUnique = source.SingleOrDefault(expr) == null;
            }
        }

        return uniqueId;
    }

这真的解决了这个问题。

答案 2 :(得分:0)

如果您调用c.L2SOnlineCountMasters转换为IEnumerable,确实会检索所有记录,如果您尝试这样做:

    public static string GetUniqueId<T, TProperty>(this IQueryable<T> source, int length, Func<T, TProperty> idProperty)
{         
bool isUnique = false;         
string uniqueId = String.Empty;         
while (!isUnique) 
{             
uniqueId = PasswordGenerator.GenerateNoSpecialCharacters(length);             
if (!String.IsNullOrEmpty(uniqueId)) 
{ 
isUnique = source.SingleOrDefault(i => idProperty(i).Equals(uniqueId)) == null;
}
}
return uniqueId;
}