Linq to SQL, выберите отдельные строки, где столбец макс? - PullRequest
1 голос
/ 11 октября 2011

EDIT: упрощенная проблема и уточненный вопрос.

Я пытаюсь преобразовать эту хранимую процедуру в оператор LINQ:

SELECT UserID, MAX(RowID) as RowID into #tempa
FROM Users
WHERE Approved = 1 
GROUP BY UserID

SELECT (bunch of columns)
FROM Users INNER JOIN #tempa
ON (Users.UserID = #tempa.UserID AND Users.RowID = #tempa.RowID)
DROP TABLE #tempa

Когда я запускаю этот SPROC, я получаю 292 строки.Когда я пытаюсь преобразовать его в LINQ, я делаю следующее:

IQueryable<User> userQuery = db.Users.Where(x => x.Approved == true);
        userQuery = userQuery.Where((x => x.RowID ==
                        db.Users.Where(u => u.UserID == x.UserID).Max(u => u.RowID)
           ));
         IList<User> users = userQuery.ToList();

Результат - 293 строки ...

Теперь я меняю SPROC на (это битовая маска, где значение 2 активно):

SELECT UserID, MAX(RowID) as RowID into #tempa
FROM Users
WHERE Approved = 1 AND (UserAttribtues & 2) = 2
GROUP BY UserID

SELECT (bunch of columns)
FROM Users INNER JOIN #tempa
ON (Users.UserID = #tempa.UserID AND Users.RowID = #tempa.RowID)
DROP TABLE #tempa

Я получаю 289 строк с помощью sproc.

Попробуйте следующее с LINQ:

 IQueryable<User> userQuery = db.Users.Where(x => (x.UserAttributes & Convert.ToInt32(UserAttributes.Active)) == Convert.ToInt32(UserAttributes.Active) && x.Approved == true);
        userQuery = userQuery.Where((x => x.RowID ==
                        db.Users.Where(u => u.UserID == x.UserID).Max(u => u.RowID)
           ));

Результат - 127 строк ....

Сначала я подумал, что в подзапросе я использовал .Max, и AD.NET исправил меня ниже, но цифры все еще далеко, что мне здесь не хватает?Я чего-то не понимаю ...

Ответы [ 2 ]

2 голосов
/ 11 октября 2011

Что-то вроде этого должно работать, вы можете рефакторировать некоторые предикаты из этого тоже.

 predicate = predicate.And((x => x.RowId == 
                                        db.Users
                                             .Where(u=>u.UserId ==x.UserId)
                                             .Max(u=>u.RowId)
                           ));

Вы можете попробовать что-то вроде этого:

var result = from u in db.Users
let max = db.Users.Where(au=>au.UserId == u.UserId).Max(au=>au.RowId)
let maxUId = db.Users.Where(au=>au.UserId == u.UserId && au.RowId == max).Select(au=>au.UserId).FirstOrDefault()
where u.RowId == max && u.UserId == maxUId
select u

Проверьте это по отношению к SQL (удалите любые другие условия, пожалуйста, для отладки). Я думаю, что пропустил часть userId, вам нужно будет сопоставить userId, иначе она не должна работать должным образом. Я уверен, что вы можете сделать запрос немного лучше, например, используйте let, чтобы сохранить весь пользовательский объект, который имеет наивысший идентификатор строки, а затем вы можете использовать объект для сопоставления и rowid, и идентификатора пользователя.

1 голос
/ 11 октября 2011
// Filter the list
var q = from s in userQuery 
    group s by s.UserId into g
     select new {UserId = g.Key, MaxRowId = g.Group.Max(s => s.RowId) } 

// Apply the filter
userQuery = userQuery.Where(i => q.Where(k => k.UserId == i.UserId && k.MaxRowId == i.RowId).Count() > 0).ToList();
...