LINQ - How to ignore empty lists in where - c#

these are my first steps with LINQ. I have two lists for filters as parameters, which can also be empty. If I execute the code this way, I don't get any values back from an empty list.
What does the code have to look like if empty lists are to be ignored?
public List<PersonDTO> GetPersons(int pageNumber, int pageSize, List<string> departments, List<string> locations, string filterText)
{
if (filterText == null)
{
filterText = "";
}
List<Person> personsList = _dbContext.Persons
.Where(a => (a.firstName.ToLower().Contains(filterText.ToLower()) || a.lastName.ToLower().Contains(filterText.ToLower()))
&& departments.Contains(a.department)
&& locations.Contains(a.location))
.Skip(pageNumber * pageSize).Take(pageSize).ToList();
return _mapper.Map<List<PersonDTO>>(personsList);
}

Handle the case that they are empty not in the query but with if:
IEnumerable<Person> persons = _dbContext.Persons;
if(!string.IsNullOrEmpty(filterText))
{
string lowerFilterText = filterText.ToLower();
persons = persons
.Where(p => p.firstName.ToLower().Contains(lowerFilterText) || a.lastName.ToLower().Contains(lowerFilterText));
}
if(departments.Any())
{
persons = persons.Where(p => departments.Contains(p.department));
}
if(locations.Any())
{
persons = persons.Where(p => locations.Contains(p.location));
}
List<Person> personList = persons.Skip(pageNumber * pageSize).Take(pageSize).ToList();
Due to LINQ's deferred execution this will execute the final query only once, at the final ToList.

See if negating Any() can help you.
Example:
string[] arr = new string[10] {"a","b","c","d","e","f","g","h","i","j"};
List<string> vowels = new List<string>() {"a","e","i","o","u"};
List<string> empty = new List<string>();
arr.Where(letter => vowels.Contains(letter));
//yields "a","e","i"
arr.Where(letter => (!empty.Any() || empty.Contains(letter)));
//yields "a","b","c","d","e","f","g","h","i","j"
Following your example, I'd chain .Where() expressions rather than putting it all into a big, single one.

You need to wrap the lists in parenthesis and use a count validation to make it optional for each list, like so:
List<Person> personsList = _dbContext.Persons
.Where(a =>
(a.firstName.ToLower().Contains(filterText.ToLower()) ||
a.lastName.ToLower().Contains(filterText.ToLower())) &&
(departments.Count == 0 || departments.Contains(a.department)) &&
(locations.Count == 0 || locations.Contains(a.location)))
.Skip(pageNumber * pageSize)
.Take(pageSize)
.ToList();
This way you switch the array conditional to an optional state, so whenever there is an item in the array !(list.Count == 0) it then tries to evaluate the filter.

You need something like this :
Why would you use Expression> rather than Func?
Expression<Func<Persons, bool>> expresionFinal = c => c.Active;
if (departments.Any())
{
Expression<Func<Persons, bool>> expresionDepartments = c => departments.Contains(p.department);
expresionFinal = PredicateBuilder.And(expresionFinal, expresionDepartments);
}
IQueryable query = dataContext.Persons;
query = query.Where(expresionFinal);

Try using .Where(s => !string.IsNullOrWhiteSpace(s)) to filter out null and empty strings entries in the list.

There are several way to check if list is empty:
1. If(list.Count() >0)
2. The best way, is to use "Any" instead of "Where" ,this will return boolian result, if true so there is some data, else there is nothing.

If you want to ignore empty list (departements and locations) in your where clause, you should be able to use Any():
public List<PersonDTO> GetPersons(int pageNumber, int pageSize, List<string> departments, List<string> locations, string filterText)
{
if (filterText == null)
{
filterText = "";
}
List<Person> personsList = _dbContext.Persons
.Where(a => (a.firstName.Contains(filterText, StringComparison.OrdinalIgnoreCase)
|| a.lastName.Contains(filterText, StringComparison.OrdinalIgnoreCase))
&& (!departments.Any() || departments.Contains(a.department))
&& (!locations.Any() || locations.Contains(a.location)))
.Skip(pageNumber * pageSize).Take(pageSize).ToList();
return _mapper.Map<List<PersonDTO>>(personsList);
}
and the code for contains:
public static class StringExtensions
{
public static bool Contains(this string source, string toCheck, StringComparison comp)
{
return source?.IndexOf(toCheck, comp) >= 0;
}
}
source: https://stackoverflow.com/a/444818/1248177

This should work. You should really build up your query before you call ToList() if you can. This will allow you to be able to do things in stages and make your application more efficient.
public List<PersonDTO> GetPersons(int pageNumber, int pageSize, List<string> departments, List<string> locations, string filterText = "")
{
List<Person> personList = new List<Person>();
if (!string.IsNullOrEmpty(filterText)) {
personsList = _dbContext.Persons
.Where(a => (a.firstName.ToLower().Contains(filterText.ToLower()) || a.lastName.ToLower().Contains(filterText.ToLower()))
&& departments.Contains(a.department)
&& locations.Contains(a.location)).ToList();
} else {
personList = _dbContext.Persons.ToList();
}
personList = personList.Skip(pageNumber * pageSize).Take(pageSize).ToList();
return _mapper.Map<List<PersonDTO>>(personsList);
}
Here is another example using IQueryable.
public List<PersonDTO> GetPersons(int pageNumber, int pageSize, List<string> departments, List<string> locations, string filterText = "")
{
IQueryable<List<Person>> personQuery = _dbContext.Persons.AsQueryable();
if (!string.IsNullOrEmpty(filterText))
{
personQuery = personQuery
.Where(a => (a.firstName.ToLower().Contains(filterText.ToLower()) || a.lastName.ToLower().Contains(filterText.ToLower()))
&& departments.Contains(a.department)
&& locations.Contains(a.location));
}
personQuery = personQuery.Skip(pageNumber * pageSize).Take(pageSize);
return _mapper.Map<List<PersonDTO>>(personQuery.ToList());
}
This is an example of how I did what you are trying to do.
public List<CourseSearchDetail> GetPaginated(SearchRequest searchRequest, bool admin, out int totalRecords,
out int recordsFiltered)
{
var query = _courseRepo
.GetDataTableQuery();
if (!admin) query = query.Where(x => x.CourseDate > DateTime.Now);
var courseList = query.ToList();
totalRecords = courseList.Count();
if (!string.IsNullOrEmpty(searchRequest.Search.Value))
courseList = courseList.Where(x => x.CourseTitle.ToLower().Contains(searchRequest.Search.Value.ToLower())).ToList();
recordsFiltered = courseList.Count();
if (searchRequest.Order == null)
courseList = courseList.OrderByDescending(x => x.CourseDate).ToList();
else
courseList = courseList.OrderResults(searchRequest);
var skip = searchRequest.Start;
var pageSize = searchRequest.Length;
courseList = pageSize > 0
? courseList.Skip(skip).Take(pageSize).ToList()
: courseList.ToList();
return courseList;
}

Related

How to get dynamic column data linq

I have following code,
public List<MemberDto> GetMembers(out int rowCount,int pageIndex,int pageSize, string seachColumn = "", string searchTerm = "", string sortBy = "", string sortDiection = "")
{
var members = (from m in context.Members
where (string.IsNullOrEmpty(searchTerm) || m.MemberNumber.Equals(searchTerm))
|| (string.IsNullOrEmpty(searchTerm) || m.LastName.Equals(searchTerm))
select m).AsEnumerable();
if (!string.IsNullOrEmpty(sortBy))
{
PropertyDescriptor prop = TypeDescriptor.GetProperties(typeof(EFModel.ClientData.Member)).Find(sortBy, true);
members = (sortDiection.ToLower() == "descnding") ? members.OrderByDescending(x => prop.GetValue(x)).ToList() : members.OrderBy(x => prop.GetValue(x)).ToList();
}
rowCount = (!string.IsNullOrEmpty(searchTerm)) ? members.Count() : rowCount = context.Members.Count() ;
members = members.Skip(pageIndex).Take(pageSize).ToList();
List<MemberDto> memberDtos = new List<MemberDto>();
mapper.Map(members, memberDtos);
return memberDtos;
}
In the above code, I seachColumn value can be ("a","b",or ""). When seachColumn = "a" I need to search table data by column MemberNumber based on searchTerm value
When seachColumn = "b" I need to search table data by column LastName. based on searchTerm value
to achieve that I wrote following code.
if(seachBy == "a")
{
var sa = (from m in context.Members
where (string.IsNullOrEmpty(searchTerm) || m.MemberNumber.Equals(searchTerm))
select m).AsEnumerable();
}
else if (seachBy == "b")
{
var sa = (from m in context.Members
where (string.IsNullOrEmpty(searchTerm) || m.LastName.Equals(searchTerm))
select m).AsEnumerable();
}
I know, I tried code is bit fool. Have any proper way to do this?
Yes there is a better way to do this. First of all you want to do this all as an IQueryable - Why? - Because as soon as you do .AsEnumerable() or .ToList() the query is executed on the DB Server and the data is loaded into Memory.
So in your code here - because you have called .AsEnumerable() it has loaded all context.Members.Where condition is true into Memory:
var members = (from m in context.Members
where (string.IsNullOrEmpty(searchTerm) || m.MemberNumber.Equals(searchTerm))
|| (string.IsNullOrEmpty(searchTerm) || m.LastName.Equals(searchTerm))
select m)
.AsEnumerable();
Your second part of code is pagination. What we normally do is write a IQueryable extension methods.
So add the following class with the 2 extension methods to a common location.
public static class IQueryableExtensions
{
public static IQueryable<T> ApplyPagination<T>(this IQueryable<T> source, string sortDirection, string sortBy, int pageNumber, int pageSize)
{
var sortDirectionInternal = sortDirection == "asc" ? "OrderBy" : "OrderByDescending";
var orderBy = sortBy;
if (pageSize != -1) // -1 is for All - I don't apply pagination if pageSize == -1.
{
return source.OrderBy(orderBy, sortDirectionInternal)
.Skip((pageNumber - 1) * pageSize)
.Take(pageSize);
}
return source.OrderBy(orderBy, sortDirection);
}
public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string ordering, string sortDirection)
{
var type = typeof(T);
// Get Property to Sort By
var property = type.GetProperty(ordering);
// If Property is NULL (not found) - Just use the first Property (Default) to ORDER BY - as this will prevent Exception
if (property == null)
{
property = type.GetProperties().First();
}
var parameter = Expression.Parameter(type, "p");
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
var orderByExp = Expression.Lambda(propertyAccess, parameter);
var resultExp = Expression.Call(typeof(Queryable), sortDirection, new[] { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExp));
return source.Provider.CreateQuery<T>(resultExp);
}
}
So now your above code will look something like this - I didn't use VS so there might be some sytnax errors:
// NOTE: you will need to include the namespace for the new IQueryableExtensions class
var members = (from m in context.Members
where (string.IsNullOrEmpty(searchTerm) || m.MemberNumber.Equals(searchTerm))
|| (string.IsNullOrEmpty(searchTerm) || m.LastName.Equals(searchTerm))
select m);
// retrieve count only if you need to of total members that match the above criteria
rowCount = members.Count();
// This is all you need to do! - ApplyPagination(params) -
members = members.ApplyPagination(sortDiection, sortBy, pageIndex, pageSize);
return mapper.Map<List<MemberDto>>(members);

C# LINQ Contains() query for autocomplete search box is slow

I've got a search box that I'm providing autocomplete suggestions for but it's really slow, it takes multiple seconds for suggestions to appear. I'm pretty sure my code is inefficient but I'm not sure the best way to improve it, any suggestions?
[HttpPost]
[Route("search")]
public virtual JsonResult Search(string term)
{
var result = new List<SearchResult>();
if (!String.IsNullOrWhiteSpace(term))
{
var searchTerms = term.ToLower().Split(' ');
List<Card> resultList = null;
foreach (var query in searchTerms)
{
if (resultList == null)
{
resultList = CardRepository.FindAll().Where(x => x.Name.ToLower().Contains(query) || x.Set.SetName.ToLower().Contains(query) || x.Variant.ToLower().Contains(query)
|| x.CardNumber.ToLower().Contains(query) || (query == "holo" && x.IsHolo)).ToList();
}
else
{
resultList = resultList.Where(x => x.Name.ToLower().Contains(query) || x.Set.SetName.ToLower().Contains(query) || x.Variant.ToLower().Contains(query)
|| x.CardNumber.ToLower().Contains(query) || (query == "holo" && x.IsHolo)).ToList();
}
}
foreach (var item in resultList.Take(10))
{
result.Add(new SearchResult()
{
label = item.FullCardName,
value = item.CardId.ToString()
});
}
}
return Json(result);
}
EDIT: Added the FindAll() code.
private readonly IDatabase _database;
public IQueryable<Card> FindAll()
{
return _database.CardDataSource.OrderBy(a => a.Name).AsQueryable();
}
SOLUTION: Going on the advice from the comments and with reference to this post Full Text Search with LINQ I moved my searching to the repository as a method and the result is almost instant autocomplete suggestions. I'm not sure how much better I could make the performance but it's easily usable in its current state.
public Card[] Search(string[] searchTerms)
{
IQueryable<Card> cardQuery = _database.CardDataSource;
foreach(var term in searchTerms)
{
var currentTerm = term.Trim();
cardQuery = cardQuery.Where(p => (p.Name.Contains(currentTerm) ||
p.Variant.Contains(currentTerm) ||
p.CardNumber.Contains(currentTerm) ||
p.Set.SetName.Contains(currentTerm) ||
(term == "holo" && p.IsHolo) ||
(term == "reverse" && p.IsHolo))
);
}
return cardQuery.Take(10).ToArray();
}
[HttpPost]
[Route("search")]
public virtual JsonResult Search(string term)
{
var result = new List<SearchResult>();
if (!String.IsNullOrWhiteSpace(term))
{
var searchTerms = term.ToLower().Split(' ');
var resultList = CardRepository.Search(searchTerms);
foreach (var item in resultList)
{
result.Add(new SearchResult()
{
label = item.FullCardName,
value = item.CardId.ToString()
});
}
}
return Json(result);
}
I think that the main problem is that you're using .FindAll() which returns a List<T>.
This means that when you say CardRepository.FindAll() it gets all of the records into an in-memory list and then your subsequent refining queries (e.g. Where(x => x.Name.ToLower().Contains(query)) and so on) are all run against the entire list. So it's right that it's returning really slowly.
You could try rewriting it by simply removing the .FindAll() and see what happens.
Please note, I'm just giving you the main problem, there are other issues, but none is as important as this one.
You could use multi-threading like this (pseudo-C# code):
var allCards = CardRepository.FindAll().ToArray(); // Ensure array.
query = query.ToUpper();
var nameTask = Task.StartNew(() => allCards.Where(x => x.Name.ToUpper().Contains(query)).ToArray());
var setTask = Task.StartNew(() => allCards.Where(x => x.Set.SetName.ToUpper().Contains(query)).ToArray());
var variantTask = Task.StartNew(() => allCards.Where(x => x.Variant.ToUpper().Contains(query)).ToArray());
var cardNumberTask = Task.StartNew(() => allCards.Where(x => x.CardNumber.ToUpper().Contains(query)).ToArray());
var holoTask = Task.StartNew(() => allCards.Where(x => query == "holo" && x.IsHolo).ToArray());
Task.WaitAll(new Task[] {nameTask, setTask, variantTask, cardNumberTask, holoTask});
var result = (nameTask.Result + setTask.Result + variantTask.Result + cardNumberTask.Result + halaTask.Result).Distinct().ToArray();

Paging Error: The method 'Skip' is only supported for sorted input in LINQ to Entities. The method 'OrderBy' must be called before the method 'Skip'

I have this following codes. I did not use a sorting just with the filtering or searching of information. I did not use skip method also. Please see codes below.
public ActionResult Index(string currentFilter=null, string search=null, string searchBy=null, int? page=1)
{
var student = from d in db.Student_vw
where d.is_active == true
select d;
if (searchBy == "default")
{
student = student.OrderByDescending(x => x.ID_Number);
}
//searching of an item
if (!String.IsNullOrEmpty(search))
{
student = student.Where(x => x.ID_Number.Contains(search) || x.student_fname.Contains(search)
|| x.student_lname.Contains(search) || x.section_name.Contains(search) || x.course_name.Contains(search)
|| x.student_address.Contains(search) || x.batch_name.Contains(search) || x.adviser_fname.Contains(search) || x.adviser_lname.Contains(search) || x.student_email_add.Contains(search));
}
else {
student = student.OrderByDescending(x => x.ID_Number);
}
ViewBag.CurrentFilter = search;
int pageSize = 25;
int pageNumber = (page ?? 1);
var returnMe = student.ToPagedList(pageNumber, pageSize);
return View(returnMe);
}
Thanks in advance for the help.
in your code, when search having value, students not ordered. do as below
public ActionResult Index(string currentFilter=null, string search=null, string searchBy=null, int? page=1)
{
var student = from d in db.Student_vw
where d.is_active == true
select d;
//if (searchBy == "default")
//{
// student = student.OrderByDescending(x => x.ID_Number);
//}
//searching of an item
if (!String.IsNullOrEmpty(search))
{
student = student.Where(x => x.ID_Number.Contains(search) || x.student_fname.Contains(search)
|| x.student_lname.Contains(search) || x.section_name.Contains(search) || x.course_name.Contains(search)
|| x.student_address.Contains(search) || x.batch_name.Contains(search) || x.adviser_fname.Contains(search) || x.adviser_lname.Contains(search) || x.student_email_add.Contains(search));
}
//else {
// student = student.OrderByDescending(x => x.ID_Number);
//}
ViewBag.CurrentFilter = search;
int pageSize = 25;
int pageNumber = (page ?? 1);
var returnMe = student.OrderByDescending(x => x.ID_Number).ToPagedList(pageNumber, pageSize);
return View(returnMe);
}
#Jen- You need to use OrderBy before student.ToPageList(pageNumber, pageSize)
SQL doesn't guarantee the order of results unless you give it an order by, so using Take or Skip (which PagedList does internally) without an order by doesn't make any logical sense and in theory could give you totally different results each time.
The way you have written your logic you can fall through without every hitting on of the order by statements.

Create a search method with AND/OR options in Linq and C#

I'm trying to create some methode for searching and filtring data in databese using c# and asp.net mvc 4 (linq)
public ActionResult Search_Names_Using_Location(string b,string d, int c=0,int Id=0)
{
ViewBag.Locations = db.Locations.ToList();
var agentlocation = new AgentLocationViewModel();
agentlocation.agents = new List<Agent>();
agentlocation.agents = (from a in db.Agents
where a.LocationId == Id
&& (a.LocationName == b)
&& (a.age > c )
select a).ToList();
return View(agentlocation);
}
The problem is that user can let some texboxes empty, so the value of Id or a or b can be null so the query will get nothing.
Is their any suggestions to do that (i can go with if else but that's hard if i have 7 or 8 strings)?
You can check for null inside query
public ActionResult Search_Names_Using_Location(string b,string d,
int c=0,int Id=0,)
{
ViewBag.Locations = db.Locations.ToList();
var agentlocation = new AgentLocationViewModel();
agentlocation.agents = new List<Agent>();
var noId = string.IsNullOrWhitespace(Id);
var noB = string.IsNullOrWhitespace(b);
agentlocation.agents = (from a in db.Agents
where (noId || a.LocationId == Id)
&& (noB || a.LocationName == b)
&& (a.age > c )
select a).ToList();
return View(agentlocation);
}
If you have AND conditions only you can use
var query = db.Agents;
if (Id != 0)
{
query = query.Where(x => x.LocationId == Id)
}
if (!string.IsNullOrWhitespace(b))
{
query = query.Where(x => x.LocationName == b)
}
...
var result = query.ToList(); // actual DB call
This will remove useless empty conditions, like WHERE (0 = 0 OR LocationId = 0)
In case of OR conditions and combinations you can take a look at PredicateBuilder
So you can use Or and And predicate combinations like this:
IQueryable<Product> SearchProducts (params string[] keywords)
{
var predicate = PredicateBuilder.False<Product>();
foreach (string keyword in keywords)
{
string temp = keyword;
predicate = predicate.Or (p => p.Description.Contains (temp));
}
return dataContext.Products.Where (predicate);
}

Create Order by programming Linq/Lambda

I have this code :
public void CreateOrdering(string field, string direction)
{
//direction : ASC/DESC
var result = context.MyTable
.Where(x => x.Code > 5)
.OrderBy()
.Skip(10)
.Take(5)
.ToList<MyTable>();
}
I rephrase, I have a method, this method receive as string field name for ordering and the direction ("ASC", "DESC")
I'd like create a Order with the field and the direction received in argument. I have to be able to :
I'd like in this Query be able to do an ascending and descending
Set the ordering field by programming, here Code may be later Id or other ...
The ordering must be done on the SQL Server side not on the list returned
Thanks,
You may use reflection in an extension method which allows for linq syntax:
public static IQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> source, string field, string direction)
{
string orderByMethod = (direction == "ASC") ? "OrderBy" : (direction == "DESC" ? "OrderByDescending" : null);
if(orderByMethod == null) throw new ArgumentException();
var propertyInfo = typeof (TSource).GetProperty(field);
var entityParam = Expression.Parameter(typeof(TSource), "e");
Expression columnExpr = Expression.Property(entityParam, propertyInfo);
LambdaExpression columnLambda = Expression.Lambda(columnExpr, entityParam);
MethodInfo orderByGeneric = typeof (Queryable).GetMethods().Single(m => m.Name == orderByMethod
&& m.GetParameters().Count() == 2
&& m.GetParameters()[0].ParameterType.GetGenericTypeDefinition() == typeof(IQueryable<>)
&& m.GetParameters()[1].ParameterType.GetGenericTypeDefinition() == typeof(Expression<>));
MethodInfo orderBy = orderByGeneric.MakeGenericMethod(new [] {typeof(TSource), propertyInfo.PropertyType});
return (IQueryable<TSource>) orderBy.Invoke(null, new object[] { source, columnLambda });
}
Sample use:
internal class SomeType
{
public string StringValue { get; set; }
}
IQueryable<SomeType> l = new List<SomeType>
{
new SomeType {StringValue = "bbbbb"},
new SomeType {StringValue = "cccc"},
new SomeType {StringValue = "aaaa"},
new SomeType {StringValue = "eeee"},
}.AsQueryable();
var asc = l.OrderBy("StringValue", "ASC");
var desc = l.OrderBy("StringValue", "DESC");
Or for your example:
context.MyTable
.Where(x => x.Code > 5)
.OrderBy(field, direction)
.Skip(10)
.Take(5)
.ToList<MyTable>();
I may have misunderstood your question, but can't you just do:
Ascending
.OrderBy(x => x.Property)
Descending
.OrderByDescending(x => x.Property)
Update
What you need is Dynamic LINQ. However, what you are trying to do it could get quite complicated. As a simple workaround you could do something like:
var result = context.MyTable
.Where(x => x.Code > 15);
if (direction == "ASC")
{
result = result.OrderBy(field);
}
else
{
result = result.OrderByDescending(field);
}
result = result.Skip(10)
.Take(5)
.ToList<MyTable>();
void Main() {
// Ascending by some other property
CreateOrdering(item => item.SomeProperty, SortDirection.Ascending).Dump("Ascending order for SomeClass.SomeProperty");
// Descending by some other property
CreateOrdering(item => item.SomeProperty, SortDirection.Descending).Dump("Descending order for SomeClass.SomeProperty");
// Ascending by the Code property
CreateOrdering(item => item.Code, SortDirection.Ascending).Dump("Ascending order for SomeClass.Code");
// Descending by the Code property
CreateOrdering(item => item.Code, SortDirection.Descending).Dump("Descending order for SomeClass.Code");
}
// I reccomend not using bare strings, and instead use an enum
public enum SortDirection {
Ascending = 0,
Descending = 1
}
// Define other methods and classes here
public List<SomeClass> CreateOrdering<T>(Expression<Func<SomeClass, T>> field, SortDirection direction) {
// query does not get executed yet, because we have not enumerated it.
var query = context.MyTable
.Where(x => x.Code > 5);
if (direction.Equals(SortDirection.Ascending)) {
query = query.OrderBy (field);
} else {
query = query.OrderByDescending (field);
}
// query gets executed when the call ToList is made.
return query.Skip(10)
.Take(5)
.ToList();
}
public static class context {
private static List<SomeClass> _MyTable = new List<SomeClass>() {
new SomeClass("A", 4), new SomeClass("B", 5), new SomeClass("C", 6),
new SomeClass("D", 7), new SomeClass("E", 8), new SomeClass("F", 9),
new SomeClass("G", 10), new SomeClass("H", 11), new SomeClass("I", 12),
new SomeClass("J", 13), new SomeClass("K", 14), new SomeClass("L", 15),
new SomeClass("M", 16), new SomeClass("N", 17), new SomeClass("O", 18)
};
public static IQueryable<SomeClass> MyTable {
get {
return _MyTable.AsQueryable();
}
}
}
public class SomeClass {
public SomeClass(string property, int code) {
this.SomeProperty = property;
this.Code = code;
}
public string SomeProperty { get; set; }
public int Code { get; set; }
}
normally you would do this:
.OrderBy(x => x.yourField)
or
.OrderByDescending(x => x.yourField)
if you need your field to be dynamic, check this answer
If the field is passed as a string (for instance when using an ObjectDataSource), you can map it using a switch:
var qry = context
.MyTable
.Where(x => x.Code > 5);
switch(orderBy) {
case "MyField": qry = qry.OrderBy(r => r.MyField); break;
case "MyField DESC": qry = qry.OrderByDescending(r => r.MyField); break;
}
// By the way, ToList can infer the generic type if you don't
// want to state it explicity
var result = qry.Skip(10).Take(5).ToList();
The query is not executed before the ToList, and at least with EF it is executed on the SQL Server. I admit the switch is quite a lot of boilerplate, but it did turn out to be quite reliable and fast.

Categories

Resources