LINQ where condition filtering - c#

String Sex = getSex(); // return M or F
String[] members = getMembers(); // return member codes in array or null
//if members array is null, no filtering for member codes
var query = from tb in MemberTable
where tb.sex.Equals(Sex) &&
(members != null ? members.Contains(tb.membercode) : true)
select tb;
The code doesn't return correct result. It returns all members no matter what members[] is.
Actually the original LINQ is complex so if there are any other possible solutions, I do not want to write the following:
if (members == null){ /*LINQ1*/ }
else { /*LINQ2*/ }
which is not a good coding style.
Any suggestion for solving this problem?

var query = MemberTable.Where(x=>x.sex.Equals(Sex))
if (members != null)
query = query.Where(x=>members.Contains(x.membercode))
//use your query
query.ToList();
OR
var query = from tb in MemberTable
where tb.sex.Equals(Sex) &&
(members == null || members.Contains(tb.membercode))
select tb;
I prefer the first.

Since || short-circuits, you should be able to do this:
var query = from tb in MemberTable
where tb.sex.Equals(Sex) &&
(members == null || members.Contains(tb.membercode))
select tb;
The (members == null || members.Contains(tb.membercode)) subexpression will be true if members is null, so Contains would not be evaluated.

var list = new List<ModelName>();
list = ctx.MemberTable
.Where(c => c.sex==Sex)
.Where(c => c.membercode==true)
.ToList();

Related

LINQ Conditional OrderBy

I'm trying to do a conditional OrderBy but it's having no effect. The List outputs the same with default ordering.
I've tried both approaches suggested in this question Conditional "orderby" sort order in LINQ
var query = _context.Groups
.Where(gr => gr.Status != ((sbyte)ActiveStatus.DELETED)
&& gr.OrganisationId == user.OrganisationId
&& (search != null && gr.Name != null ? (gr.Name.Contains(search)) : true == true)
)
.Select(GroupReportModel.Projection);
if(!pager.Sort.HasValue || pager.Sort.Value == ((int)Sort.MODIFIED))
query.OrderByDescending(gr => gr.Created.Date);
if(pager.Sort.Value == ((int)Sort.NAME))
query.OrderByDescending(gr => gr.Name);
pager.TotalRecords = query.Count();
var list = query.Skip(pager.PageCount != null ? pager.PageCount.Value * (pager.Page.Value) : 0)
.Take(pager.PageCount != null ? pager.PageCount.Value : 0)
.ToList();
LINQ methods do not mutate the query object, they return a new one, you need to reassign it:
if(!pager.Sort.HasValue || pager.Sort.Value == ((int)Sort.MODIFIED))
query = query.OrderByDescending(gr => gr.Created.Date);
if(pager.Sort.Value == ((int)Sort.NAME))
query = query.OrderByDescending(gr => gr.Name);
....

Linq "where" condition with nullable object property result in "invoke non static method requires a target"

I've tried to find a similar question but I haven't found exactly what I want.
I have this issue: about the following code I am not able to find a way to manage that if devTab is null then his property ID is not available and the where condition t.IDDevTab ==devTab.ID leads to null reference error. Mind that t.IDDevTab is not nullable in the DB. I have tried to insert some additional conditions to the Where but it resulted in error: invoke non static method requires a target. I would obtain a empty list in "DeviceTabColumnsNameAndDesc" if "devTab" is null!
DeviceTable devTab = (from t in _db.DeviceTables
where t.DeviceType == devtype && t.IDPlant == id
select t)
.FirstOrDefault();
var DeviceTabColumnsNameAndDesc = (from t in _db.DeviceTabCols
where t.IDDevTab == devTab.ID
&& t.MeasureFamily != "KEY"
&& t.MeasureFamily != "DATETIME"
select new
{
colName = t.ColumnName,
colDescr = t.ColumnDescr
})
.ToList();
Is there a workaround of this problem? Thank you in advance.
So, if devTab is null you want a new empty list of anonymous type.. Awkward, but doable:
DeviceTable devTab = (from t in _db.DeviceTables
where t.DeviceType == devtype && t.IDPlant == id
select t)
.FirstOrDefault();
var DeviceTabColumnsNameAndDesc = devTab == null ?
Enumerable.Empty<object>().Select(x => new { colName = "", colDescr = "" }).ToList() :
(
from t in _db.DeviceTabCols
where t.IDDevTab == devTab.ID && t.MeasureFamily != "KEY" && t.MeasureFamily != "DATETIME"
select new {
colName = t.ColumnName,
colDescr = t.ColumnDescr
}
).ToList();
If you wanted to switch away from anonymous types in this case, you could look at ValueTuple:
var DeviceTabColumnsNameAndDesc = devTab == null ?
new List<(string colName, string colDesc)>() :
(
from t in _db.DeviceTabCols
where t.IDDevTab == devTab.ID && t.MeasureFamily != "KEY" && t.MeasureFamily != "DATETIME"
select (
colName: t.ColumnName,
colDescr: t.ColumnDescr
)
).ToList();
Or make a record, which is like a class but with some extra bits that make it useful as a data holder:
//defined in a namespace
public record ColThing(string ColName, string ColDesc);
var DeviceTabColumnsNameAndDesc = devTab == null ?
new List<ColThing>() :
(
from t in _db.DeviceTabCols
where t.IDDevTab == devTab.ID && t.MeasureFamily != "KEY" && t.MeasureFamily != "DATETIME"
select new ColThing(t.ColumnName, t.ColumnDescr)
).ToList();

LINQ with Contains return zero rows if i am passing empty string

i don't know how to handle this in LINQ
simply i have a searchKey in which i am passing user enter data and it return with rows. but if i am not passing any searchkey it not given any data. i dont want to add contains if searchkey is empty :(
var AppointmentList = (from app in Con.ios_Appointment
where (app.IS_DELETED == false && app.CLINICIANID == appReq.id
&& app.FNAME.Contains(appReq.searchKey.Trim()) || app.LNAME.Contains(appReq.searchKey.Trim()) || app.ADDRESS.Contains(appReq.searchKey.Trim())
)
orderby app.DATE descending
select new
{
app.ID,
app.FNAME,
app.LNAME,
app.DATE,
app.LONGITUDE,
app.LATITUDE,
app.ADDRESS,
app.STATUS,
app.START_TIME
}).Skip(skipRecord).Take(Convert.ToInt32(record)).ToList();
I suggest you use method syntax to easily build the query up programatically:
var query = Con.ios_Appointment.Where(app => !app.IS_DELETED && app.CLINICIANID == appReq.id);
var search = appReq.searchKey.Trim();
if (search != "")
{
query = query.Where(app => app.FNAME.Contains(search) ||
app.LNAME.Contains(search) ||
app.ADDRESS.Contains(search));
}
var appointments = query
.OrderByDescending(app => app.DATE)
.Select(app => new
{
app.ID,
app.FNAME,
app.LNAME,
app.DATE,
app.LONGITUDE,
app.LATITUDE,
app.ADDRESS,
app.STATUS,
app.START_TIME
})
.Skip(skipRecord)
.Take(Convert.ToInt32(record))
.ToList();
You need to use string.IsNullOrWhiteSpace method:
where (app.IS_DELETED == false &&
app.CLINICIANID == appReq.id &&
(string.IsNullOrWhiteSpace(appReq.searchKey) ||
app.FNAME.Contains(appReq.searchKey.is Trim()) || ...

how to create dynamic linq query based on search criterias

I have a search form which i want to use to search a database for data. The searchbox has 4 checkboxes and 1 textfield. The problem is how do i build the linq query considering i dont know beforehand what textboxes the user will check for filtering the search. What i have so far is:
[HttpPost]
public ActionResult search(string ulv, string bjorn, string jerv, string gaupe)
{
var query = (from o in db.observasjonene select o);
if (ulv != null)
{
query = query.Where(o => o.art == ulv);
}
if (bjorn != null)
{
query = query.Where(o => o.art == bjorn);
}
if (jerv != null)
{
query = query.Where(o => o.art == jerv);
}
if (gaupe != null)
{
query = query.Where(o => o.art == gaupe);
}
IEnumerable ls = query.ToList();
return Json(ls, JsonRequestBehavior.AllowGet);
}
The problem with the "where" clause is that if a condition is true, it overwrites the results from the earlier condition. I guess i need an "or" statement or something..
If I have understood your question correctly, you want to check if art equals to any of provided values. You can combine those values into collection and check if collection contains art value:
var values = new [] { ulv, bjorn, jerv, game }.Where(v => v != null);
var query = from o in db.observasjonene
where values.Contains(o.art)
select o;
EF translates Contains into SQL IN operator.
I'm using two approaches in this case:
Build dynamic query:
var q = DB.Invoices.AsQueryable();
if (isPresented != null)
q = q.Where(iv => iv.IsPresented == isPresented);
if (ID != null)
q = q.Where(iv => iv.ID == ID.Value);
...........................
return from iv in q
orderby iv.DueDate descending
select iv;
Use Union to combine search results:
var q1 = db.FeeInvoice.Where(fi => [QUERY1]));
if (isPresented != null)
{
var q2 = db.FeeInvoice.Where(fi =>[QUERY2]));
q1.Union(q2);
}
if (ID != null)
{
var q3 = db.FeeInvoice.Where(fi =>[QUERY3]);
q1.Union(q3);
}
...........................
You are comparing all the parameters value to single column in the query ie. art (see you have written same column name in each where condition) . I'm not sure why are you doing so? you can simply take single parameter which compare the value like this
public ActionResult search(string value)
{
query = query.Where(o => o.art == value);
}
or if it is by mistake and you want to apply where condition along with multiple column then you can try something like this
query=query.Where(o => (o.art == ulv || ulv == string.Empty) && (o => o.bjorn == bjorn || bjorn=string.empty) && (o.jerv == jerv || jerv == string.Empty) && (o.gaupe == gaupe || gaupe == string.Empty));
Note: I assume your column name as your parameters name.

Why Count() is not work for null record of "Var" or "iQueryable" class?

[Invoke]
public List<string> GetConCurrentContractId(string identity, string empId, string payMonth)
{
List<string> _rtn = new List<string>();
IQueryable<mContract> query = this.ObjectContext.mContract;
IQueryable<mContract> query2 = this.ObjectContext.mContract.Where(
q => q.wEmpId == empId && q.wEmpId == "NOTVALID");
if (query.Count()>0)
{
_rtn.ToList<string>();
}
return _rtn;
}
query has record return, and query.Count() work,
and query2.count() return exception ...
What is optional way to know any record return?
From your title I'm guessing you get a NullReferenceException. The most likely way I can see this happening only for query2 is if one of the items in mContract is null. To ignore these null objects you can do this:
IQueryable<mContract> query2 = this.ObjectContext.mContract.Where(
q => q != null && q.wEmpId == empId && q.wEmpId == "NOTVALID");
1) Why: because tha autors implemented the method this way.
2) How to solve it: You can create your own extensions method, which accepts null in IEnumerable argument and returns original instance or empty collection (array) for null value:
public static IEnumerable<T> NotNullEnum<T>( this IEnumerable<T> o ) {
if ( object.ReferenceEquals( o, null ) {
return new T[0];
}
else {
return o;
}
}
IQueryable<mContract> query2 = this.ObjectContext.mContract.NotNullEnum().Where(
q => q.wEmpId == empId && q.wEmpId == "NOTVALID");
var count = query2.Count();

Categories

Resources