2011-01-12 4 views
2

У меня есть очень специфический запрос LINQ. Я хотел бы проверить наличие случайно сгенерированного ключа в таблице.Выражение 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; 
} 

Однако я заметил, что этот метод сначала выбирает все записи из таблицы, который передается в качестве источника, а затем запускает ИНЕК. Такое поведение, очевидно, занимает много времени. Так что в основном это делает SELECT * FROM Products, а затем запускает SingleOrDefault

Есть ли способ, которым я мог бы непосредственно выполнить запрос таким образом, что он делает Select * из продуктов WHERE Id = «XXXXXXX»

Вот пример того, как я его называю :

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

в этом случае L2SOnlineCountMasters представляет собой таблицу, в Databse и с представляет собой экземпляр DataContext.

В надежде, что на это будет дан ответ!

Cheerz, Anup

ответ

1

После прочтения обоих комментариев я понял, что IQueryable следует использовать. Однако «Equals» в Expression Call не работает, поскольку он вызывает следующую ошибку: «Несколько методов« Equals »в типе« System.String »совместимы с прилагаемыми аргументами». Таким образом, я немного изменил код следующим образом:

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; 
    } 

Это действительно решило проблему.

+0

У кого-нибудь есть хорошие указатели на выражения? Оказывается, мои понятия немного нечеткие и, к сожалению, я не могу найти хорошую (и я имею в виду хорошую) документацию по основным принципам выражений, функций и т. Д. –

+0

Ваш код выглядит отлично. Обратите внимание, что вы можете сделать это намного быстрее путем кэширования 'typeof (string) .GetMethod (« Equals », new [] {typeof (string)})' в статическом поле. – SLaks

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; 
} 
+0

Это не поможет. См. Мой ответ. – SLaks

1

Двигатель LINQ к 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>.

+0

Хорошо, я думаю, это помогло! Вот что я придумал на основе вашего предложения. См. Мой ответ ниже. –

Смежные вопросы