✅ IEnum and IQueryable usage.

My Controller action is here.
public async Task<IActionResult> Index(IndexViewModel model, string? filter, SortOption? sort, int? pageIndex)
{
var decks = _mtgDbContext.Decks.AsEnumerable();
var decksIQ = _mtgDbContext.Decks.AsQueryable();


if (!string.IsNullOrEmpty(filter))
{
decks = decks.Where(t => t.Name.Contains(filter, StringComparison.OrdinalIgnoreCase));
}

if (sort is { } s)
{
decks = s switch
{
SortOption.NameDesc => decks.OrderByDescending(t => t.Name),
SortOption.NameAsc => decks.OrderBy(t => t.Name),
_ => decks.OrderBy(t => t.Name)
};
}

var deckIQ = decks.AsQueryable();
var pageSize = _configuration.GetValue("PageSize", 3);
var paginatedList = await PaginatedList<Deck>.CreateAsync(decksIQ, pageIndex ?? 1, pageSize);

model.Decks = paginatedList;
model.Filter = filter;
model.Sort = sort;
return View(model);
}
public async Task<IActionResult> Index(IndexViewModel model, string? filter, SortOption? sort, int? pageIndex)
{
var decks = _mtgDbContext.Decks.AsEnumerable();
var decksIQ = _mtgDbContext.Decks.AsQueryable();


if (!string.IsNullOrEmpty(filter))
{
decks = decks.Where(t => t.Name.Contains(filter, StringComparison.OrdinalIgnoreCase));
}

if (sort is { } s)
{
decks = s switch
{
SortOption.NameDesc => decks.OrderByDescending(t => t.Name),
SortOption.NameAsc => decks.OrderBy(t => t.Name),
_ => decks.OrderBy(t => t.Name)
};
}

var deckIQ = decks.AsQueryable();
var pageSize = _configuration.GetValue("PageSize", 3);
var paginatedList = await PaginatedList<Deck>.CreateAsync(decksIQ, pageIndex ?? 1, pageSize);

model.Decks = paginatedList;
model.Filter = filter;
model.Sort = sort;
return View(model);
}
The pagination example from docs uses IQueryable so I was doing this to get the IEnum from the sorting part above to work with it.
var deckIQ = decks.AsQueryable();
var pageSize = _configuration.GetValue("PageSize", 3);
var paginatedList = await PaginatedList<Deck>.CreateAsync(decksIQ, pageIndex ?? 1, pageSize);
var deckIQ = decks.AsQueryable();
var pageSize = _configuration.GetValue("PageSize", 3);
var paginatedList = await PaginatedList<Deck>.CreateAsync(decksIQ, pageIndex ?? 1, pageSize);
It says decksIQ is equal to the filtered down decks Enum after processing the first line, but the third line when passing decksIQ in the parameter says it's the full unfiltered list again. Why would this happen?
7 Replies
BigggMoustache
BigggMoustache16mo ago
Here's the pagination method
public class PaginatedList<T> : List<T>
{
public int PageIndex { get; private set; }
public int TotalPages { get; private set; }

public PaginatedList(List<T> items, int count, int pageIndex, int pageSize)
{
PageIndex = pageIndex;
TotalPages = (int)Math.Ceiling(count / (double)pageSize);

this.AddRange(items);
}

public bool HasPreviousPage => PageIndex > 1;

public bool HasNextPage => PageIndex < TotalPages;
public static async Task<PaginatedList<T>> CreateAsync(IQueryable<T> source,
int pageIndex, int pageSize)
{
var count = 0;
foreach (var item in source) { count++; };
var newSource = await source.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync();
return new PaginatedList<T>(newSource, count, pageIndex, pageSize);
}

}
public class PaginatedList<T> : List<T>
{
public int PageIndex { get; private set; }
public int TotalPages { get; private set; }

public PaginatedList(List<T> items, int count, int pageIndex, int pageSize)
{
PageIndex = pageIndex;
TotalPages = (int)Math.Ceiling(count / (double)pageSize);

this.AddRange(items);
}

public bool HasPreviousPage => PageIndex > 1;

public bool HasNextPage => PageIndex < TotalPages;
public static async Task<PaginatedList<T>> CreateAsync(IQueryable<T> source,
int pageIndex, int pageSize)
{
var count = 0;
foreach (var item in source) { count++; };
var newSource = await source.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync();
return new PaginatedList<T>(newSource, count, pageIndex, pageSize);
}

}
Saber
Saber16mo ago
you realize deckIQ and decksIQ are not the same variable right
BigggMoustache
BigggMoustache16mo ago
oh my gosh. I wonder how many problems I didn't need to try and solve. I do have a particular question about this too, I'm just seeing if that fixed it before asking and changing the subject 🤣 Okay that brings me back to my first problem.
InvalidOperationException: The source 'IQueryable' doesn't implement 'IAsyncEnumerable<MTGDeckBuilder.DataModels.Deck>'. Only sources that implement 'IAsyncEnumerable' can be used for Entity Framework asynchronous operations.
Saber
Saber16mo ago
You shouldn't be calling AsEnumerable() on the dbset
BigggMoustache
BigggMoustache16mo ago
Oh alright. I had tried getting the sorting / filter if statements to work with an IQueryable but I couldn't figure it out
InvalidOperationException: The LINQ expression 'DbSet<Deck>() .Where(d => d.Name.Contains( value: __filter_0, comparisonType: OrdinalIgnoreCase))' could not be translated. Additional information: Translation of method 'string.Contains' failed. If this method can be mapped to your custom function, see https://go.microsoft.com/fwlink/?linkid=2132413 for more information. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
Sorry m8 I just don't understand what this is telling me. Okay so I can't use that Contains(asdf, StringComparison) bit
Saber
Saber16mo ago
its saying it doesn't understand how to translate that contains method to sql
BigggMoustache
BigggMoustache16mo ago
Yeah I got that part bud. sorry wasn't meant to sound snary. Just saying I understand that much. I'm finding there isn't an option for this in EFcore. Should I just ToUpper or something before saving to database and search accordingly? Well that worked for now. Thanks for the help. I could have sworn I tried this at the beginning and it didn't work but 🤷🏻‍♂️ . Probably something goofy like another typo.