linq 用于选择字段的链接表达式

mpgws1up  于 2022-12-27  发布在  其他
关注(0)|答案(3)|浏览(137)

我有一个非常具体的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示例。

qaxu7uf2

qaxu7uf21#

在阅读了这两个注解之后,我意识到应该使用IQueryable。但是,表达式调用中的“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;
    }

这真的解决了问题。

soat7uwm

soat7uwm2#

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>

v8wbuo2f

v8wbuo2f3#

实际上,如果调用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;
}

相关问题