Судя по вашим комментариям, вам нужно сделать как можно больше этого в базе данных. Предполагая, что книги и пользовательские подписки хранятся в одном и том же месте, вы можете объединить запрос предпочтений пользователя с поиском по таблице книг, чтобы получить нужный результат.
Ради аргумента предположим, что у вас есть несколько таблиц, которые выглядят примерно так, как POCO:
[Table("Books")]
public class Book
{
public int ID { get; set; }
public int Genre { get; set; }
public string Name { get; set; }
public string Author { get; set; }
public Date PublishDate { get; set; }
}
[Table("Genres")]
public class Genre
{
public int ID { get; set; }
public string Name { get; set; }
}
[Table("Users")]
public class User
{
public int ID { get; set; }
public string Name { get; set; }
}
[Table("UserGenrePreferences")]
public class UserGenrePreference
{
public int User { get; set; }
public int Genre { get; set; }
}
Для примера у нас есть один жанр на книгу, и в таблице UserGenrePreferences
нет дубликатов.
Базовый порядок может выглядеть примерно так:
// get genre preferences for the selected user
var userPrefs =
from pref in context.UserGenrePReferences
where pref.User == userID
select new { Genre = (int?)pref.Genre };
var result =
from book in context.Books
join pref in userPrefs on book.Genre equals pref.Genre
into prefTemp
from pref in prefTemp.DefaultIfEmpty()
orderby (pref.Genre == null ? 1 : 0), book.ID
select book;
Это внешнее объединение с жанровыми предпочтениями пользователя. Книги с соответствующим жанром будут иметь ненулевое значение в соответствующей записи pref
, поэтому в результате они будут помещены перед несопоставленными книгами. В этом случае нумерация страниц выполняется обычным .Skip(...).Take(...)
методом.
Для очень больших наборов данных это все еще займет некоторое время для запуска. Если вы ожидаете, что пользователь будет перелистывать данные, было бы неплохо получить только идентификаторы книг и кэшировать их в памяти. Возьмите первые несколько тысяч результатов и, например, ищите больше при необходимости. Затем возьмите записи книги, когда пользователь захочет их получить, что будет намного быстрее, чем выполнение запроса выше для каждой страницы.
Если, с другой стороны, ваши данные о пользовательских предпочтениях не находятся в той же базе данных, вы можете использовать метод Contains
для выполнения заказа.
Предполагая, что у вас в памяти есть массив идентификаторов жанров, вы можете сделать это:
int[] userPrefs = new int[] { 1, 2, 3, 5 };
var result =
from book in context.Books
orderby (userPrefs.Contains(book.Genre) ? 0 : 1), book.ID
select book;
В зависимости от ORM это будет выглядеть примерно так:
SELECT *
FROM Books
ORDER BY
CASE WHEN Genre = 1 OR Genre = 2 OR Genre = 3 OR Genre = 5 THEN 0 ELSE 1 END,
ID
Это может быть довольно быстро, но если список предпочтений очень большой, он может быть медленнее.