Выражение Linq для выбора поля - PullRequest
3 голосов
/ 12 января 2011

У меня очень специфический запрос 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

. Можно ли каким-либо образом напрямую выполнить запрос, чтобы он выполнял Select * from Products WHERE Id = 'XXXXXXX'

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

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

В этом случае L2SOnlineCountMasters - это таблица в базе данных, а c - это экземпляр DataContext.

Надеемся получить ответ на этот вопрос!

Cheerz, Anup

Ответы [ 3 ]

1 голос
/ 12 января 2011

Механизм 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 голос
/ 12 января 2011

Прочитав оба комментария, я понял, что следует использовать IQueryable.Однако «Равные» в вызове выражения не работает, поскольку выдает следующую ошибку: «Более одного метода« Равные »для типа« 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 голосов
/ 12 января 2011

Действительно, все записи будут извлечены, если вы вызовете приведение 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;
} 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...