LINQ - Where Conditions - "if-else" Cases - c#

I have following Linq query. What I want is if I do search for a particular year, I should get corresponding records of that year. Else just show records of current year. Same way searchtext has also to be done.
public ActionResult Search(string searchtext, int? year)
{
string selyear = year.ToString();
string curyear = (DateTime.Now.Year).ToString();
hdms = from t in db.HOLIDAY
where
(year == null || t.DOH.StartsWith(selyear)) &&
(searchtext == "" || t.HOLIDAY_NAME == searchtext)
select new HOLIDAYDETAILS
{
DOH = t.DOH,
};
....
}
I want to satisfy this also if (year == null) then t.DOH.StartsWith(curyear) and
if (searchtext == "") then t.HOLIDAY_NAME != "Sunday" && t.HOLIDAY_NAME != "Saturday".
Also If both are null at the same time, both conditions should be satisfied together.
How can I give this one too on the above where clause?

If checking year is null or not is your problem then you simply can do like this-
public ActionResult Search(int? year)
{
string selyear = year.ToString();
string queryyear = (string.IsNullOrEmpty(selyear)) // checking for null
? (DateTime.Now.Year).ToString() // current year
: selyear; // year in query
hdms = from t in db.HOLIDAY
join t1 in db.EMPLOYEE on t.UPDATED_BY equals t1.EMP_CODE
where
t.DOH.StartsWith(queryyear) // comparing queryyear
orderby
t.DOH
select new HOLIDAYDETAILS
{
DOH = t.DOH,
};
....
}
Hope this will works for you...

public ActionResult Search(int? year)
{
string curyear = (DateTime.Now.Year).ToString();
string selyear = year!=null? year.ToString() : curyear;
var query = from t in db.HOLIDAY
join t1 in db.EMPLOYEE on t.UPDATED_BY equals t1.EMP_CODE
select new {t,t1};
query = query.Where(o=>o.t.DOH.StartsWith(selyear));
if (searchtext == "")
{
query = query.Where(o=>o.t.HOLIDAY_NAME != "Sunday" && o.t.HOLIDAY_NAME != "Saturday");
}
hdms = query.OrderBy(o=>o.t.DOH).Select(o=> new HOLIDAYDETAILS
{
DOH = o.t.DOH,
});
....
}

Related

Linq query where Contains() checks for list of strings

Consider the Following Query:
var query = from o in this.OrderManager.LoadOrders()
join s in this.SkuManager.LoadSkus() on o.SKU equals s.SKU
where o.ORDER_ID == orderId
let parcelItem = o.RPU != "Y" && o.DROP_SHIP != "Y" && s.TRUCK_SHIP != "T" && o.SKU != "ABC-123" && o.SKU != "XYZ-789" && o.SKU != "JKL-456"
select new OrderMailLineItem
{
OrderId = o.ORDER_ID,
Sku = s.SKU,
WarehouseId = s.SITE_ID,
QualifyingItem = qualifyingItem,
OversizedItem = parcelItem && (s.DROP_SHIP == null)
};
I would like to be able to write the line let parcelItem = ... to be more like !o.SKU.Contains(skuList) where:
List<string> skuList = new List<string> { "ABC-123", "XYZ-789", "JKL-456"};
You should check whether SKU is not in list instead of checking whether list is in SKU:
let parcelItem = !skuList.Contains(o.SKU)
!skuList.Contains(o.SKU) is exactly how you'd usually do it.
But you could write an In operator, if you like:
public static class ExtensionMethods
{
public static bool In<T>(this T t, params T[] values)
=> values.Contains(t);
}
...
let parcelItem = o.RPU != "Y" && o.DROP_SHIP != "Y" && s.TRUCK_SHIP != "T" &&
!o.SKU.In("ABC-123", "XYZ-789", "JKL-456")
I doubt that'll work with Linq to SQL though.
I don't see why this wouldn't work. You would just need to check those three Yes/No flags in addition to your SKU list.
var skuList = new[] { "ABC-123", "XYZ-789", "JKL-456"};
var query = from o in this.OrderManager.LoadOrders()
join s in this.SkuManager.LoadSkus() on o.SKU equals s.SKU
where o.ORDER_ID == orderId
let parcelItem = o.RPU != "Y" && o.DROP_SHIP != "Y" && s.TRUCK_SHIP != "T" && skuList.Contains(o.SKU)
select new OrderMailLineItem
{
OrderId = o.ORDER_ID,
Sku = s.SKU,
WarehouseId = s.SITE_ID,
QualifyingItem = qualifyingItem,
OversizedItem = parcelItem && (s.DROP_SHIP == null)
};

IQueryable with only optional parameters

I currently have the following method:
public List<Order> GetOrders(int profileId, string timeSpan, string workOrd, string partNo, bool includeDeleted)
{
DateTime startDate = DateTime.Now;
DateTime endDate = DateTime.Now;
string[] times = (!string.IsNullOrWhiteSpace(timeSpan)) ? timeSpan.Trim().Split('-') : new string[] { "", "" };
if (!string.IsNullOrWhiteSpace(times[0]) && !string.IsNullOrWhiteSpace(times[0]))
{
startDate = DateTime.Parse(times[0]).Date;
endDate = DateTime.Parse(times[1]).Date;
}
//New Real Query
IQueryable<Order_Travel> otQuery = _context.Order_Travels.Where(x =>
(profileId != 0 || x.Profile.ProfileID == profileId)
&& ((timeSpan == null || timeSpan.Trim() == "") || ((DbFunctions.TruncateTime(x.TimeRecieved) >= startDate)
&& (DbFunctions.TruncateTime(x.TimeRecieved) <= endDate)))
&& ((workOrd == null || workOrd.Trim() == "") || x.Order.WorkOrdNo == workOrd)
&& ((partNo == null ||partNo.Trim() == "") || x.Order.PartNo == partNo)
&& (!includeDeleted || x.Aborted == true));
//The results is now in order_travel. Under here binding them to a list of orders with only the respective orderTravels included.
List<Order> orders = new List<Order>();
List<Order_Travel> ots = otQuery.ToList();
foreach (Order_Travel ot in ots)
{
var OrderInList = orders.FirstOrDefault(X => X == ot.Order);
if (OrderInList == null)
{
orders.Add(ot.Order);
OrderInList = orders.FirstOrDefault(X => X == ot.Order);
OrderInList.OrderTravels.Clear();
OrderInList.OrderTravels.Add(ot);
}
else
{
OrderInList.OrderTravels.Add(ot);
}
}
return orders;
}
What I need it to do, is (as I've attempted) to make a call, finding all Order_Travel objects that match the paramters sent to it. If some (or all) are left blank, it takes everything, regardless of the values.
The code right now, does not return anything, if a blank search is made (a search that does not have any parameters), and I can not see what could be the issue. I have tried debugging it, but with no luck.
Any help would be greatly appreciated!
Thanks!
Filter one option at a time, instead of trying to put everything into a single expression:
IQueryable<T> query = all; // start with everything
if (IsPresent(option1))
{
query = query.Where(t => t.XXX == option1);
}
Example
IQueryable<Order_Travel> otQuery = _context.Order_Travels;
if (profileId != 0)
{
otQuery = otQuery.Where(x => x.Profile.ProfileID == profileId);
}
if (timeSpan != null && timeSpan.Trim() != "")
{
otQuery = otQuery.Where(x => DbFunctions.TruncateTime(x.TimeRecieved) >= startDate &&
DbFunctions.TruncateTime(x.TimeRecieved) <= endDate);
}
You will also find this easier to maintain than one huge expression.
Probably this part is your problem:
(profileId != 0 || x.Profile.ProfileID == profileId)
It should be
(profileId == 0 || x.Profile.ProfileID == profileId)
If your profile ID is 0, it will only find entries with x.Profile.ProfileID being 0. Probably there are no such entries.

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);
}

How to write Linq expression using external objects

I am trying to convert a loop in to a linq expression. But it seams not to work the way i am doing it:
var customer = GetCustomerFromDatabase(id);
ICollection<Order> customerOrders = null;
if (customer == null)
{
LogAndThrowCustomerNotFound(id);
}
else
{
customerOrders = customer.Orders;
}
customer.YearToDateSales = 0.0;
customer.CurrentSales = 0.0;
DateTime today = DateTime.Now;
if (customerOrders != null)
foreach (var order in customerOrders)
{
if (order.SubmittedDate != null
&& order.SubmittedDate.Value.Year.CompareTo(today.Year) == 0)
{
customer.YearToDateSales += (double)order.OrderTotal;
}
if (order.SubmittedDate != null
&& (order.SubmittedDate.Value.Month.CompareTo(today.Month) == 0
&& order.SubmittedDate.Value.Year.CompareTo(today.Year) == 0))
{
customer.CurrentSales += (double)order.OrderTotal;
}
}
So I came up with that expression to get the customer orders that match the current year... bot it does not work. in he expression order is empty and today is conflicting. I i create
DateTime today = DateTime.Now; in the parm of the expression i get different errors...
IEnumerable<Order> cOrders = customerOrders
.Where((ICollection<Order> order , today) =>
order.SubmittedDate.Value.Month == today.Month);
It's simpler if you just don't attempt pass today into the lambda, it'll be closed into the expression anyway;
customer.YearToDateSales = customerOrders
.Where(x => x.SubmittedDate != null &&
x.SubmittedDate.Value.Year == today.Year)
.Sum(x => x.OrderTotal);
customer.CurrentSales = customerOrders
.Where(x => x.SubmittedDate != null &&
x.SubmittedDate.Value.Month == today.Month &&
x.SubmittedDate.Value.Year == today.Year)
.Sum(x => x.OrderTotal);
Hard to tell exactly what's wrong without the error, but you probably need to check for null on the SubmittedDate like in the original version:
IEnumerable<Order> cOrders = customerOrders
.Where((ICollection<Order> order , today) =>
order.SubmittedDate.HasValue &&
order.SubmittedDate.Value.Month == today.Month);

Categories

Resources