How to check if array is not null in LINQ? - c#

I Have this where statement in LINQ:
(users != null && users.Contains(x.Appointment.UserId))
users is an int[]. When i run this code i have an exception:
Unable to create a null constant value of type 'System.Int32[]'. Only
entity types, enumeration types or primitive types are supported in
this context.
What should i do?

I had a similar problem. Assuming you are starting with something like this:
var filtered = appointments
.Where(x => users != null && users.Contains(x.Appointment.UserId));
As #CarstenKönig suggests, try moving the null check outside of the Where clause:
var filtered = users != null ?
appointments.Where(x => users.Contains(x.Appointment.UserId)) :
appointments;
That means the null check is handled by C#, and LINQ to Entities doesn't attempt to convert it to SQL.

As others suggested you could move bool check outside the closure and use resulting bool in your Where statement:
var usersNotNull = users != null;
var users = users == null ? new string[0] : users;
query.Where(x => usersNotNull && users.Contains(x.Appointment.UserId));

Related

How to check if IQueryable element/ item contains a property in C#?

I have an IQueryable as follows
var issues = from i in jira.Issues.Queryable
where i.Project == project.Key
orderby i.Created
select i;
I am trying to get the count where issue type is Bug like this:
TotalIssues = issues.ToList().Where(i => i.Type.Name == "Bug").Count();
The problem here is there are some issues without a type. How can I check if the issue type exists?
You can try null propagation ?. in order to have null for Name if any item or item.Type are null:
TotalIssues = issues
.AsEnumerable() // Linq to objects from now on; no need in materialization
.Count(item => "Bug".Equals(item?.Type?.Name)); // just count
You don't want issues without type. You can keep code simple by not taking issues without type into account.
var bugsCount = issues.AsEnumerable()
.Where(issue => issue.Type != null)
.Count(issue => issue.Type.Name == "Bug");
You can chain as much .Where clauses as you wish, items will be still enumerated only once.
What do you mean? Some issues don't have Type Property? Or Some issues's property Type is null?
If it is some issues don't have Type Property, I think you can specify issues's class or interface. Or you can use reflection.
If it is some issues's property Type is null, you can check Type is not null first.
From your comment, I think i may be null too.
i!=null && i.Type!=null && i.Type.Name=="Bug"

MySQL Entity Framework With LinQ Correlated Query Not Executing

I am using Visual Studio 2012 with MySQL 5.7 Community Edition. I am getting object reference not set to an instance of object on the below query.
var oList = (
from dm in dbContext.document_master
join um in dbContext.user_master on dm.Alocated_CAA equals um.UserId
where (dm.DocumentHandle != null)
select new TaskLogReport
{
documentDate = dm.Document_Date,
documentHandle = dm.DocumentHandle,
fileNumber = dm.FileNumber,
statusRemarks = dbContext.statushistories
.Where(x => x.DocumentHandle == 12345678).FirstOrDefault().Remarks
}).ToList();
In the above query If I get change 12345678 to dm.DocumentHandle, then getting object reference not set to an instance object.
Try with MS-SQL server , working fine.
You get the error because FirstOrDefault() returns null, because there are no objects who's DocumentHandle equals dm.DocumentHandle. Changing dm.DocumentHandle to 12345678 works because there is one matching element.
This line is the problem:
.Where(x => x.DocumentHandle == 12345678).FirstOrDefault().Remarks
C#'s Enumerable.FirstOrDefault() method returns either the first matching element of an enumerable, or, if there aren't any, the default value of the type. In the case of nullable types, FirstOrDefault() returns null if no elements are found.
The reason you get no error when you use 12345678 is because there is at least one matching value with that DocumentHandle. However, when you change that to dm.DocumentHandle, no matching elements are found, causing FirstOrDefault to return null. Then you essentially do null.Remarks, which causes the error.
You should change your code to this:
.FirstOrDefault(x => x.DocumentHandle == dm.DocumentHandle)?.Remarks
There are two differences here:
Got rid of the where and moved the predicate to the FirstOrDefault call. This is just a cleaner way of doing what you were doing before.
Added the ? at the end of the FirstOrDefault call. That is the null propagation operator.
What it does is it turns this:
int foo;
if (bar != null)
{
foo = bar.foo;
}
Into this:
int foo = bar?.foo;
Now, if there are matching elements, statusRemarks will be equal to the first one's Remarks. Otherwise, statusRemarks will be null.
EDIT: The null propagation operator was implemented in C# 6.0, which is .Net 4.6 onwards, so it won't work in .Net 4.0.
You'll have to modify your query and implement a check, like so:
var oList = (
from dm in dbContext.document_master
join um in dbContext.user_master on dm.Alocated_CAA equals um.UserId
where (dm.DocumentHandle != null && dbContext.statushistories.Count(x => x.DocumentHandle == dm.DocumentHandle) > 0)
select new TaskLogReport
{
documentDate = dm.Document_Date,
documentHandle = dm.DocumentHandle,
fileNumber = dm.FileNumber,
statusRemarks = dbContext.statushistories.First(x.DocumentHandle == dm.DocumentHandle).Remarks
}).ToList();

Can a C# method allow nullable lists as parameters?

I'm trying to write a method that allows for a list of Ids to search for, but I would like to allow the list to be optional. I've seen examples of List<string> but I'm having trouble with List<Guid>.
Trying this method in LinqPad, I get the message:
Unable to create a null constant value of type 'System.Collections.Generic.List`1[[System.Guid, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]'. Only entity types, enumeration types or primitive types are supported in this context.
Here's the method:
public static ICollection<Project> GetProjectsAllowed
(
this IMkpContext db,
Guid profileId,
List<Guid> profOrgIds = null
)
{
var projects = (from p in db.Project.Include(p => p.Proposals)
join po in db.ProfileOrganization on p.CreatedById equals po.ProfileId
where (profOrgIds == null || profOrgIds.Contains(po.OrganizationId))
&& p.IsActive && po.IsActive
select p);
return projects.ToList();
}
UPDATE: Thanks to your comments, here's what I did:
public static ICollection<Project> GetProjectsAllowed
(
this IMkpContext db,
Guid profileId,
List<Guid> profOrgIds = null,
List<Guid> projectIds = null
)
{
var projects = (from p in db.Project.Include(p => p.Proposals)
where p.IsActive
select p);
if (profOrgIds != null && profOrgIds.Any())
{
var profileIds = db.ProfileOrganization
.Where(po => po.IsActive && profOrgIds.Contains(po.OrganizationId))
.Select(po => po.ProfileId);
projects = projects.Where(p => profileIds.Contains(p.CreatedById));
}
if (projectIds != null && projectIds.Any())
projects = projects.Where(proj => projectIds.Contains(proj.ProjectId));
return projects.ToList();
}
A C# method can accept null lists. The problem you have is with the LINQ query itself.
You cannot pass a NULL check on the profOrgIds list into an Entity Framework related LINQ query, since the Entity Framework LINQ provider (which is in use here, as you are executing LINQ queries against an EF database context object) has no way to translate the query syntax into equivalent T-SQL.
In other words, get rid of
profOrgIds == null
from the query and you should be fine, but you will need to check profOrgIds is null before you call the query.
The problem has nothing to do with the optional List<Guid> parameter. The offending line is in the LINQ query, and is a limitation of Entity Framework:
where (profOrgIds == null...
Essentially, Entity Framework doesn't know how to turn this into an equivalent SQL query.
A possible solution is to turn the condition into into a boolean, which EF should be able to handle (admittedly, this is untested):
var listIsNull = profOrgIds == null;
var projects = (from p in db.Project.Include(p => p.Proposals)
join po in db.ProfileOrganization on p.CreatedById equals po.ProfileId
where (listIsNull || profOrgIds.Contains(po.OrganizationId))
&& p.IsActive && po.IsActive
select p);
Issue is that null Lists choke Entity Framework.
Put this before the query
profOrgIds = profOrgIds ?? new List<Guid>();
and remove the null-checking, code should be fixed.

Entity Framework - Linq to Entities - Optional filter

I am struggling to figure out how to get a LINQ statement to produce a specific WHERE clause in SQL in a single statement.
I am after it producing something like this:
SELECT ColA, ColB, ColC, ColN...
FROM Orders
WHERE Client = #ClientId
AND (#CompanyId IS NULL OR #CompanyId = CompanyId)
My (failing) LINQ statement looks like this:
var includeAllCompanies = company == null;
var data = context.Orders.Where(o => o.Client.Id == clientId
&& (includeAllCompanies
|| (c.Company != null && c.Company.Id == company.Id)).ToList();
However, it always throws an exception when the variable company is NULL (it works fine when it has been initialised). The exception being:
Non-static method requires a target.
My current fix is to split my LINQ statement into two. One using an Expression<Func<>> (to be transformed to a SQL statement with partial filtering). Then another that uses Func<> to perform the remaining filters on the returned list.
Expression<Func<>> to let SQL do some of the work (excluding nullable objects)
var data = context.Orders.Where(o => o.Client.Id == clientId).ToList();
Func<> to then filter out the nullable objects
data = data.Where(c => (territory == null
|| (c.Territory != null && c.Territory.Id == territory.Id))).ToList();
This works, however, I want SQL to be performing this query.
The problem is that, company is server-side variable. Regardles includeAllCompanies value, EF has to translate whole LINQ query to SQL - and in this case SQL doesn't know what is company.Id - so EF has to always get company.Id value in order to put into SQL query. Even if company is null (so that is why you get exception). I hope you see my point, if not - I'll try to give some sample.
In order get rid of exception you can do the following:
var companyId = company == null ? null : (int?)company.Id;
var data = context.Orders.Where(o => o.Client.Id == clientId
&& (companyId == null
|| (c.Company != null && c.Company.Id == companyId)).ToList();

Checking For null in Lambda Expression

In the code below I am trying to get the null, empty string, and source components out of a List. I have not tested this code yet but my intuition tells me it will break when filtering the List for source and empty string if it comes by a null value.
I tried to extract the null values first, but I am still filtering the base List. How can I re-write this code to accomplish what I am trying to do in the best way?
List<LineItem> nullList=itemsList.Where(s => s[Constants.ProductSource] == null)
.ToList();
NALineItems = itemsList.Where(s => s[Constants.ProductSource] == source
|| s[Constants.ProductSource] == String.Empty)
.ToList();
NALineItems = nullList.Union(NALineItems).ToList();
s[Constants.ProductSource] is an attachment property to Microsoft ECommerce PurchaseOrder object. Its basically another property of an object.
Based on "I am trying to get the null, empty string, and source components out of a List" I assume you mean you want a list with these 3 specific values.
var allItems = itemsList
.Where(s => string.IsNullOrEmpty(s[Constants.ProductSource])
|| s[Constants.ProductSource] == source)
.ToList()
Is there a reason you cannot combine the expression into one? I would also add a check that the key exists in the dictionary:
List<LineItem> NALineItems = itemsList.Where(s =>
s.ContainsKey(Constants.ProductSource) && (
String.IsNullOrEmpty(s[Constants.ProductSource]) ||
s[Constants.ProductSource] == source))
.ToList();

Categories