我有一个非常具体的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, 阿努普
答案 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;
}