var results = (from bk in bookContext.Books
orderby bk.id descending
select bk).ToList();
表“Book”也具有类型id,并且如果用户订阅特定类型,则在列出建议书籍时,我想首先按那些订阅类型排序,然后按书籍ID排序。我可以在下面的列表中获得订阅的流派ID列表。
List<int> subGenereIds = new List<int>() { 10, 12, 22 };
如何将按部分的顺序添加到上面的初始Linq查询中,以便用户首先获得列表中具有流派id的书籍,之后的其余部分?
您需要在内存中进行排序,因为没有办法将该排序逻辑传递给SQL。您可以通过使用AsEnumerable()
将上下文从SQL查询更改为内存中查询来实现:
var results = bookContext.Books
.AsEnumerable()
.OrderByDescending(bk => bk.Id)
.ThenBy(bk => subGenereIds.IndexOf(bk.Id));
从您的评论中看起来您需要尽可能多地在数据库中完成此操作。假设您将书籍和用户订阅存储在同一个位置,您可以将用户首选项的查询与书籍表的搜索结合起来,以获得您所追求的结果。
为了论证,让我们假设你有一些看起来像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(...)
方法处理分页。
对于非常大的数据集,这仍然需要一些时间来运行。如果您期望用户将通过数据进行分页,那么抓住书籍ID并将其缓存在内存中可能是个好主意。获取前几千个结果,并在需要时寻找更多结果。然后在用户需要时抓取书籍记录,这比在每个页面上运行上述查询要快得多。
另一方面,如果您的用户首选项数据不在同一个数据库中,您可以使用Contains
方法进行排序。
假设您在内存中只有一个类型ID数组,那么您应该能够这样做:
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
这可能相当快,但如果首选项列表非常大,则可能会更慢。
我不建议您编写更复杂的linq查询来解决它。
是的,它变得越来越短,但也越来越难以阅读。下面的答案越长。你可以自己缩短它。
首先,您应该获得具有subGenereIds列表的genreIds的那些。
var onesWithGenreIdFromList = (from bk in bookContext.Books
where subGenereIds.Contains(bk.genreId).orderby bk.Id descending select bk).ToList();
然后从列表中获取列表的其余部分(那些没有subGenereIds列表的genreId)。
var results = (from bk in bookContext.Books
where !subGenereIds.Contains(bk.genreId)
orderby bk.id descending
select bk).ToList();
作为最后一步,您应该将第一个列表添加到第二个列表以创建您想要的订单:
onesWithGenreIdFromList.AddRange(results);
var lastResults = onesWithGenreIdFromList;
快乐的编码!