That My Linq query
var result = db.APPLICATIONS
.Where(a => Statuses.Contains(a.STATUS_ID))
.Where(a => a.TrackingNo == TrackingNo)
Statuses is a int list and TrackingNo is a nullable int (int?).
Problem:
If the TrackingNo is null then i dont want to run this clause or just skip this condition.
LINQ queries can be built in multiple steps:
var result = db.APPLICATIONS
.Where(a => Statuses.Contains(a.STATUS_ID));
if (TrackingNo != null)
{
result = result.Where(a => a.TrackingNo == TrackingNo);
}
Note that if you have a Select (a projection), you probably must build the query in multiple steps in multiple variables:
var result2 = result.Select(a => new { a.STATUS_ID });
with the result2 "built" after the if.
You can check a nullable int by using its "HasValue" property.
var result = db.APPLICATIONS
.Where(a => Statuses.Contains(a.STATUS_ID))
.Where(a => a.HasValue && (a.TrackingNo == TrackingNo))
This will cause it to evaluate the "HasValue" prior to checking the value itself. If HasValue return false, then it will never evaluate the rest of the expression (and thus not cause NullReferenceException).
If it is of type "int?", then this will work.
Just add && condition and check null. And you can use 1 where condiiton here why second where.Pls try this:
var result = db.APPLICATIONS
.Where(a => Statuses.Contains(a.STATUS_ID)
&& a.TrackingNo!=null
&& a.TrackingNo == TrackingNo)
You should first check the values of the filtering parameters before trying to add more stuff to the store expression. This would only apply the Statuses and TrackingNo filtering if the nullable TrackingNo has a value. Otherwise it will return all APPLICATIONS as IQueryable.
var result = db.APPLICATIONS.AsQueryable();
if (TrackingNo.HasValue)
{
result = result.Where(a => Statuses.Contains(a.STATUS_ID) && a.TrackingNo == TrackingNo);
}
return result;
Alternatively, this would check if you have any statuses to apply and the tracking separatedly.
var result = db.APPLICATIONS.AsQueryable();
if (Statuses != null && Statuses.Count() > 0)
{
result = result.Where(a => Statuses.Contains(a.STATUS_ID));
}
if (TrackingNo.HasValue)
{
result = result.Where(a => a.TrackingNo == TrackingNo);
}
return result;
Or third option, as it is unclear what you really wanted. This would apply the statuses filtering always and tracking only if it is available
var result = db.APPLICATIONS.Where(a => Statuses.Contains(a.STATUS_ID));
if (TrackingNo.HasValue)
{
result = result.Where(a => a.TrackingNo == TrackingNo);
}
return result;
Related
I have used this to pick just a single column from the collection but it doesn't and throws casting error.
ClientsDAL ClientsDAL = new DAL.ClientsDAL();
var clientsCollection= ClientsDAL.GetClientsCollection();
var projectNum = clientsCollection.Where(p => p.ID == edit.Clients_ID).Select(p => p.ProjectNo).ToString();
Method:
public IEnumerable<Clients> GetClientsCollection(string name = "")
{
IEnumerable<Clients> ClientsCollection;
var query = uow.ClientsRepository.GetQueryable().AsQueryable();
if (!string.IsNullOrEmpty(name))
{
query = query.Where(x => x.Name.Contains(name));
}
ClientsCollection = (IEnumerable<Clients>)query;
return ClientsCollection;
}
As DevilSuichiro said in comments you should not cast to IEnumerable<T> just call .AsEnumerable() it will keep laziness.
But in your case it looks like you do not need that at all because First or FirstOrDefault work with IQueryable too.
To get a single field use this code
clientsCollection
.Where(p => p.ID == edit.Clients_ID)
.Select(p => p.ProjectNo)
.First() // if you sure that at least one item exists
Or (more safe)
var projectNum = clientsCollection
.Where(p => p.ID == edit.Clients_ID)
.Select(p => (int?)p.ProjectNo)
.FirstOrDefault();
if (projectNum != null)
{
// you find that number
}
else
{
// there is no item with such edit.Clients_ID
}
Or even simpler with null propagation
var projectNum = clientsCollection
.FirstOrDefault(p => p.ID == edit.Clients_ID)?.ProjectNo;
I have the following Entity Framework function that it joining a table to a list. Each item in serviceSuburbList contains two ints, ServiceId and SuburbId.
public List<SearchResults> GetSearchResultsList(List<ServiceSuburbPair> serviceSuburbList)
{
var srtList = new List<SearchResults>();
srtList = DataContext.Set<SearchResults>()
.AsEnumerable()
.Where(x => serviceSuburbList.Any(m => m.ServiceId == x.ServiceId &&
m.SuburbId == x.SuburbId))
.ToList();
return srtList;
}
Obviously that AsEnumerable is killing my performance. I'm unsure of another way to do this. Basically, I have my SearchResults table and I want to find records that match serviceSuburbList.
If serviceSuburbList's length is not big, you can make several Unions:
var table = DataContext.Set<SearchResults>();
IQuerable<SearchResults> query = null;
foreach(var y in serviceSuburbList)
{
var temp = table.Where(x => x.ServiceId == y.ServiceId && x.SuburbId == y.SuburbId);
query = query == null ? temp : query.Union(temp);
}
var srtList = query.ToList();
Another solution - to use Z.EntityFramework.Plus.EF6 library:
var srtList = serviceSuburbList.Select(y =>
ctx.Customer.DeferredFirstOrDefault(
x => x.ServiceId == y.ServiceId && x.SuburbId == y.SuburbId
).FutureValue()
).ToList().Select(x => x.Value).Where(x => x != null).ToList();
//all queries together as a batch will be sent to database
//when first time .Value property will be requested
Can anyone see anything wrong with the ternary in the where of this linq statement:
var organizations = Context.Set<Domain.Content.Organisation>()
.Where(x => x.ShowCompanyPage == (showCompanyPagesOnly ? true : x.ShowCompanyPage))
if showCompanyPagesOnly is set to true, I get 4 results, this is correct only four companies have ShowCompanyPage = true.
However if I set it to false, I expect 1000+ results (all companies). But I STILL only get 4.
Is my logic not:
if showCompanyPagesOnly is true, then give me results where x.ShowCompanyPage == true
else give me results where x.ShowCompanyPage = whatever is in the column (ie ALL Organisations)
?
x.ShowCompanyPage is a nullable bool column.
Full code:
public Result<IList<Organisation>> GetAllOrganisations(bool showCompanyPagesOnly = false)
{
var result = new Result<IList<Organisation>>();
try
{
var organizations = Context.Set<Domain.Content.Organisation>()
.Where(x => x.ShowCompanyPage == (showCompanyPagesOnly == true ? true : x.ShowCompanyPage)) // show only company pages or show all
.AsNoTracking()
.Select(x => new DataContracts.Content.Organisation
{
Id = x.Id,
Name = x.Name,
OrganisationTypeId = x.OrganisationTypeId,
IsCustomer = x.IsCustomer,
SeoName = x.SeoName,
Description = x.Description,
Website = x.Website
}).OrderBy(x => x.Name).ToList();
result.Data = organizations;
}
catch (Exception ex)
{
result.SetException(ex);
HandleError(ex);
}
return result;
}
Sometimes when logic is getting too complex the best answer is the turn the question upside down, currently you are asking
if showCompanyPagesOnly is true how do i get only the ones with with ShowCompanyPage = true
if you swap that with get everything unless showCompanyPagesOnly is true and your logic becomes a simple OR statement
either showCompanyPagesOnly is not true or ShowCompanyPage is true
which is
x => (!showCompanyPagesOnly) || x.ShowCompanyPage
you may need to make that
x => (!showCompanyPagesOnly) || (x.ShowCompanyPage ?? false)/*default value depends on if you want to treat null as true or false*/)
to take into account the nullability
This is a much better approach, as it will generate two distinct LINQ queries, and this will allow SQL Server to generate two distinct query plans, which can in most cases greatly affect the performance of the queries:
public Result<IList<Organisation>> GetAllOrganisations(bool showCompanyPagesOnly = false)
{
var result = new Result<IList<Organisation>>();
try
{
var organizations = Context.Set<Domain.Content.Organisation>()
.AsNoTracking();
if (showCompanyPagesOnly)
organizations=organization
.Where(x => x.ShowCompanyPage == true);
result.Data = organizations
.Select(x => new DataContracts.Content.Organisation
{
Id = x.Id,
Name = x.Name,
OrganisationTypeId = x.OrganisationTypeId,
IsCustomer = x.IsCustomer,
SeoName = x.SeoName,
Description = x.Description,
Website = x.Website
}).OrderBy(x => x.Name).ToList();
}
catch (Exception ex)
{
result.SetException(ex);
HandleError(ex);
}
return result;
}
Try this:
.Where(x => showCompanyPagesOnly ? x.ShowCompanyPage == true : true)
Here is a fiddle.
The Where() function returns records that satisfy the condition, so the condition must evaluate to a Boolean (i.e. either true or false). If you put the value true in the condition, then you're effectively asking the Where() function to return all records. It is similar to:
if(true){
//do something.
}
As you know this will always execute the "do something".
I have the following code which returns correctly IF I have ALL four strings filled. However, if one of those strings is empty, the list returned is empty. Basically, I need it to return a list even if 1 or more or even ALL of the strings are empty.
private List<Search> FilterSearchResults(List<Search> results)
{
string _dataType = cmbISDataType.SelectedItem.ToString();
string _medium = cmbISMedium.SelectedItem.ToString();
string _pStatus = cmbISPStatus.SelectedItem.ToString();
string _rStatus= cmbISRStatus.SelectedItem.ToString();
return results
.Where(a => a.Data_Type == _dataType && !string.IsNullOrWhiteSpace(_dataType))
.Where(b => b.Medium == _medium && !string.IsNullOrWhiteSpace(_medium))
.Where(c => c.PStat== _pStatus && !string.IsNullOrWhiteSpace(_pStatus ))
.Where(d => d.RStatus== _rStatus && !string.IsNullOrWhiteSpace(_rStatus))
.ToList();
}
Thanks in advance.
Rather than checking whether or not the value is null in every single iteration of the loop, only perform the check when the string is not null:
private List<Search> FilterSearchResults(List<Search> results)
{
string _dataType = cmbISDataType.SelectedItem.ToString();
string _medium = cmbISMedium.SelectedItem.ToString();
string _pStatus = cmbISPStatus.SelectedItem.ToString();
string _rStatus = cmbISRStatus.SelectedItem.ToString();
IEnumerable<Search> query = results;
if (!string.IsNullOrWhiteSpace(_dataType))
query = query.Where(a => a.Data_Type == _dataType);
if (!string.IsNullOrWhiteSpace(_medium))
query = query.Where(b => b.Medium == _medium);
if( !string.IsNullOrWhiteSpace(_pStatus))
query = query.Where(c => c.PStat == _pStatus);
if( !string.IsNullOrWhiteSpace(_rStatus))
query = query.Where(d => d.RStatus == _rStatus);
return query.ToList();
}
Your current condition specifies that any of the strings can't be null or empty which is why the list is being returned as empty. A where clause in Linq works by returning any object in the collection that satisfies the specified condition. If you were to specify the condition as simply:
results.Where(true);
All objects would be returned.
Using an OR instead of an AND for the is null or empty check will return any object in the list that evaluates true for either of conditions. Therefore if the filter string is empty all objects will be returned, otherwise only the objects which meet the other conditions will be returned.
Update your filters to:
return results
.Where(a => a.Data_Type == _dataType || string.IsNullOrWhiteSpace(_dataType))
.Where(b => b.Medium == _medium || string.IsNullOrWhiteSpace(_medium))
.Where(c => c.PStat== _pStatus || string.IsNullOrWhiteSpace(_pStatus ))
.Where(d => d.RStatus== _rStatus || string.IsNullOrWhiteSpace(_rStatus))
.ToList();
I have the following two statements :-
var isadminByuser = tms.SecurityRoles.Where(a => a.Name.ToLower() == "administrator")
.Select(a=>a.SecurityRoleUsers.Where(a2 => a2.UserName.ToLower() == user.ToLower()));
if (isadminByuser.Count() >= 1) { return true;}
&
var adminByGroup = tms.SecurityRoles.Where(a => a.Name == "Administrator")
.SingleOrDefault().Groups
.Select(a2 => a2.TMSUserGroups
.Where(a3 => a3.UserName.ToLower() == user.ToLower()));
bool isadminByGroup = adminByGroup.Count() >= 1;
The first var isadminByuser will always have elements (will always be >=1), even if the where clause a3.UserName.ToLower() == user.ToLower())) is false, while the other var will have a count of zero is the where clause (a3.UserName.ToLower() == user.ToLower())) is false. So why will the first var never have a count of zero?
Thanks
The answer to the question asked is that you are selecting an IQueryable<SecurityRoleUsers> when you select
a.SecurityRoleUsers.Where(a2 => a2.UserName.ToLower() == user.ToLower())
which may or may not have a count of 0, but the containing query will return one of these IQueryables for each SecurityRole that matches Name = "administrator", hence the count will always be 1+ if there is at least one matching SecurityRole
Update:
// first get SecurityRoles
bool isadminByuser = tms.SecurityRoles.Where(a => a.Name.ToLower() == "administrator")
// now you're only interested in the related SecurityRoleUsers
.SelectMany( a => a.SecurityRoleUsers )
// now check if any of the SecurityRoleUsers meet your criteria
.Any( sru => sru.UserName.ToLower() == user.ToLower() );
Could you observe sql query differences from ms-sql-profiler
tms.SecurityRoles.Where(a => a.Name.ToLower() == "administrator")
.Select(a=>a.SecurityRoleUsers.Where(a2 => a2.UserName.ToLower() == user.ToLower()));
***
tms.SecurityRoles.Select(a=>a.SecurityRoleUsers.Where(a2 => a2.UserName.ToLower() == user.ToLower())).Where(a => a.Name.ToLower() == "administrator");