Where condition equal true and Nullable object must have a value - c#

I've been looking for an answer but I couldn't find anything to help me. I get this error
Nullable object must have a value.
My request is:
from e in dc.tblElements
where
e.IsUnique &&
(e.TypeID == 2) &&
(categoryId != null ? e.CategoryId.Value == categoryId.Value : true) &&
((e.Name.Contains(keyword)) ||
(e.Keywords.Contains(keyword)))
select e
The third line of the where condition is the problem (categoryId). If categoryId has a value, it works but not when it is null. However, I replaced this line with true and it works as well. I can't understand what is the problem here.
in my table CategoryId can be null so I tried:
(categoryId.HasValue && e.CategoryId.HasValue ? e.CategoryId.Value == categoryId.Value : true)
What I want to do: I want to select all the elements of this table depending on the where condition. categoryId comes from a drop down so if the default value is still selected when the user does the request, I want to display all the elements no matter what the category.

You should be good with just comparing your two variables:
e.CategoryId == categoryId
If you want special treatment of one being NULL, maybe because you want that to be a special case where NULL matches everything instead of just another NULL, you can add that:
e.CategoryId == categoryId || !e.CategoryId.HasValue || !categoryId.HasValue
Your problem with your statement is that you access .Value. Yes, if you would run the code with Linq-To-Objects in memory, it would work because the compiler will only run the code of one branch of your if-statement (ternary operator, I know, but you get what I mean). But for a database, there needs to be a statement prepared. That statement needs to be there in full, it does not use any short-circuiting. So the statement builder will access both your branches to build that statement for the database and one of those branches will fail because it accesses .Value although there is none.

Make CategoryId as nullable type and try.
Nullable<int> CategoryId = null;

Looks like you are trying to implement a "catch-all" categoryId parameter. That's an anti-pattern in SQL and a strong smell that can lead to bad performance.
In LINQ, it's not necessary since you can add .Where() conditions just by adding another .Where() call to your query, eg :
var query = from e in dc.tblElements
where
e.IsUnique &&
e.TypeID == 2 &&
( e.Name.Contains(keyword) ||
e.Keywords.Contains(keyword) )
select e;
if (categoryId.HasValue)
{
query=query.Where(e.CategoryId == categoryId);
}
You can use this to add multiple conditions at runtime

Try this:
from e in dc.tblElements
where
e.IsUnique &&
(e.TypeID == 2) &&
(categoryId.HasValue && e.CategoryId.Value == categoryId.Value) &&
((e.Name.Contains(keyword)) ||
(e.Keywords.Contains(keyword)))
select e

Related

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

LINQ search query doesn't work

I'm trying to write a search query in LINQ. Below is the where condition.
where (!string.IsNullOrEmpty(nameWithInitials)
&& tb.NameWithInitials.Contains(nameWithInitials))
&& (!string.IsNullOrEmpty(studentRegNo)
&& tbSR.StudentRegistrationNo.Contains(studentRegNo))
&& (!string.IsNullOrEmpty(NIC) && tb.NIC.Contains(NIC))
&& (!string.IsNullOrEmpty(fullName) && tbi.Name.Contains(fullName))
It doesn't return any values if I pass a single parameter. For example if I pass 'Chamara' as fullname it doesn't return any result but if I pass all the parameters at the once then it returns the matching records.
I need to get this to work even when I pass several parameters dynamically
You are using AND (&&) everywhere, so if at least one of these conditions is false, your where condition will be false. Try using OR conditions instead:
where (string.IsNullOrEmpty(nameWithInitials) || tb.NameWithInitials.Contains(nameWithInitials))
&& (string.IsNullOrEmpty(studentRegNo) || tbSR.StudentRegistrationNo.Contains(studentRegNo))
&& (string.IsNullOrEmpty(NIC) || tb.NIC.Contains(NIC))
&& (string.IsNullOrEmpty(fullName) || tbi.Name.Contains(fullName))
In this case in any of these conditions if you have empty parameter, only the first part of condition will be evaluated, otherwise the second condition will be evaluated.
One potential issue is that Entity Framework might not be able to translate this to actual SQL. In this case, you can use such approach:
var query = // your original query without where condition
// Check if the condition is valid and only then add where condition
if(!string.IsNullOrEmpty(nameWithInitials))
{
query = query.Where(tb => tb.NameWithInitials.Contains(nameWithInitials));
}
// repeat this for all other conditions
What you're asking is semi-confusing but i think you want to search for every string if exists, which translates to
where ((string.IsNullOrEmpty(nameWithInitials)
|| tb.NameWithInitials.Contains(nameWithInitials))
&& (string.IsNullOrEmpty(studentRegNo)
|| tbSR.StudentRegistrationNo.Contains(studentRegNo))
&& (string.IsNullOrEmpty(NIC) || tb.NIC.Contains(NIC))
&& (string.IsNullOrEmpty(fullName) || tbi.Name.Contains(fullName))

WHERE clause in LINQ statement that pulls specific match or everything if no match found

I am trying to write a LINQ statement that will pull all the items from a table where the column Type matches what the user selects in a dropdown menu but if no matches are found then it returns ALL the items from the table regardless of the Type. I have gotten it to return all the items that match the user’s selection but I cannot figure out what code needs to be added so that if no matches are found it defaults to pulling all the items in the table.
Current Code:
(from i in db.ItemTypeTranslations
join st in db.SectionTranslations
on i.ItemType.SectionID equals st.SectionID
where i.CultureID == 1 && i.ItemType.SectionID == SelectedSection
select new
{
st.SectionID,
st.Title,
i.ItemTypeName
}).ToList();
You can use the ? operator to turn your where clause into a conditional and have your current select as the successful branch and the select that returns everything as the unsuccessful branch.
Similar question asked on MSDN
How about
where i.CultureID == 1 && (i.ItemType.SectionID == SelectedSection || String.IsNullOrEmpty(SelectedSection))
I am assuming that SelectedSection is a string. If not, the principle will be the same: Where (SectionID == SelectedSection OR SelectedSection == some-default-value)
Edit: I just re-read your question, and realized that I'm answering the wrong question.
Thanks Maggy May. That helped me a lot I ended up with this code that looks to be working:
(from i in db.ItemTypeTranslations
join st in db.SectionTranslations
on i.ItemType.SectionID equals st.SectionID
where (SelectedSection == 0 ? true : i.ItemType.SectionID == SelectedSection) && i.CultureID == 1
select new
{
i.ItemTypeID,
st.Title,
i.ItemTypeName
}).ToList();

Comparing String Column with Int column

I'm working on EF CTP5 Code First development with an existing database. I need to get the data from two tables by comparing columns of different types.
For example - Here p.ColumnA is varchar as q.ColumnA is int but the values might be the same for few records. So, I'm trying to do Convert.ToInt32 which does not work. I do not have complete control over the database to modify the table.
from p in context.TableA
from q in context.TableB
where p.ColumnZ == "ABC" &&
(p.ColumnA == null || Convert.ToInt32(p.ColumnA) == q.ColumnA) &&
(p.ColumnB == null || p.ColumnB == q.ColumnB)
select p.ColumnC
Can someone suggest a solution? Thanks.
When you write a linq statement that interacts with the entityframework it trys to convert all the commands to SQL. Because there is no sql command for Convert.ToInt32 it is throwing an error.
This post describes a way to cal the sql functions for converting types. It should help you.
As the other posters have explained, LINQ to SQL Entities doesn't know how to translate Convert.ToInt32 into a SQL expression (LINQ to SQL can apparently handle this). From what I can tell, it doesn't support int.Parse, either. But since you're just doing an equality comparison (rather than greater/less than), you should be able to achieve the same result by converting the int to a string, rather than converting the string to an int.
from p in context.TableA
from q in context.TableB
where p.ColumnZ == "ABC" &&
(p.ColumnA == null || p.ColumnA == q.ColumnA.ToString()) &&
(p.ColumnB == null || p.ColumnB == q.ColumnB)
select p.ColumnC

Possible to do this in linq?

I am wondering if something like this could be done(of course what I have written does not work but that's what I am essentially trying to achieve) .
var test = u.Owner;
a.Table.Where(u => test == true)
I have a linq query that I want to reuse(basically I got a query that I use 5 times) and the only thing that changes is what I am comparing against.
So in the above u.Owner is compared against true. In another query it would look the same but instead of u.Owner I might have u.Add == true or u.Edd == true.
So is there a way I can sort of reuse what I have. Of course in my code the query is a bit longer but I just shortened down.
Edit
Basically the whole query
List<Permission> clearence = user.PermissionLevels.Where(u => u.Id == Id &&( u.Add == permissionNeeded || u.Permission.Name == PermissionTypes.Owner)).ToList();
permissionNeeded == Enum
So my orignal way of doing it was u.Permission.Name == permissionNeeded so I compared the enum value to a string.
Now my db model has change and I need to check against 5 different permissions separately that are bools and not strings.
u.Add = true || u.Owner == true;
u.Edit = true || u.Owner == true;
u.Delete= true || u.Owner == true;
u.View= true || u.Owner == true;
Thats all changes for the entire query so that's why I am trying to make it into one query(just like I had it before).
So I am thinking of having a switch statement. The method still takes in a permissionNeeded(enum) I then go through and determine what clause I need and some how insert it into the query.
switch(PermssionNeeded)
{
case PermissionTypes.Add:
u.Add;
break;
// all other cases here.
}
Take advantage of the fact that Where can have any function taking type Table as a parameter and returning a boolean to create a function like:
public IQueryable<Table> QueryTables(Func<Table, bool> testFunction)
{
return a.Table.Where(testFunction).AsQueryable<Table>();
}
Edit: (in addition to edit to add AsQueryable above, which I earlier forgot)
If all you want to do is vary the boolean field used in the test, and you don't want to have to specify an entire function (which you're about to find out is much easier), you would need to use some reflection:
using System.Reflection;
public IQueryable<Table> QueryTables(PropertyInfo pi)
{
return a.Table.Where(t => (bool)(pi.GetGetMethod().Invoke(t, null))).AsQueryable<Table>();
}
To construct the PropertyInfo object, use something like:
PropertyInfo pi = typeof(Table).GetProperty("Owner");
I prefer the earlier method, but I did want to show that something like this is at least possible.
If you only want to specify the property you are checking you can do
public IEnumerable<Table> GetTables(Func<Table,bool> getValue)
{
return a.Table.Where(table => /*some common filter*/)
.Where(table => getValue(table))
}
var query = from u in uSrc join v in vSrc on u.ID equals v.RelatedUID
where v.Valid && u.Created < DateTime.UtcNow.AddDays(-365)
select u; // relatively complicated starting point.
var q1 = query.Where(u => u.Add); // must also have Add true
var q2 = query.Where(u => u.Test); // must also have Test true
var q3 = query.Where(u => u.ID < 50); // must also have ID < 50
And so on.
Edit:
Okay, so your starting query is:
List<Permission> clearence = student.PermissionLevels.Where(u => u.Id == Id &&( u.Add == permissionNeeded || u.Permission.Name == PermissionTypes.Owner)).ToList();
However, note that this creates a list, so any further work done on it will be a matter of Linq-to-objects. We'll come back to that in a minute, as it's sometimes good and sometimes not.
Now, if I understand you correctly, you need different sets for different cases, which you can do with your query as per:
var set0 = clearance.Where(u.Add = true || u.Owner == true);
var set1 = clearance.Where(u.Edit = true || u.Owner == true);
var set2 = clearance.Where(u.Delete= true || u.Owner == true);
var set3 = clearance.Where(u.View= true || u.Owner == true);
Now, this will work, but may not be the best approach. If we go back to the original query, we don't have to do ToList(), but can have:
IQueryable<Permission> clearence = student.PermissionLevels.Where(u => u.Id == Id &&( u.Add == permissionNeeded || u.Permission.Name == PermissionTypes.Owner));
Now, in the first case because we built a list we first got all values that matched the critera backed, and then stored it in memory, in clearance.
In the second case, clearance doesn't store any values at all, but instructions on how to get them.
The question is which is better to use. In the case where we are going to end up using the vast majority of the objects returned by the first query on its own, then there is a performance boost in using the list version, because they are loaded into memory only once, and then taken from memory without hitting the database again.
However, in most cases, it's better to do the second version for two reasons:
We hit the database in each case, but only retrieve the objects needed in that case.
We don't store anything in memory longer than necessary. Above a certain amount this is an important performance matter in itself.
The time to first item is faster this way.
We can further refine, for example if we do the following:
var trimmed = from set0 select new{u.Id, u.Permission.Name};
The we retrieve anonymous objects with Id and Name properties that are all we care about for a particular case, and not all of the relevant fields are retrieved from the database, or other source.
I've recently come to prefer a Dictionary over switch statements. You could store all your lambas in a Dictionary<PermissionNeeded, Func<User, bool>> that would look like this:
Dictionary<PermissionNeeded, Func<User, bool>> Permissions =
new Dictionary<PermissionNeeded, Func<User, bool>> {
{ PermissionNeeded.Add, u => u.Add }, // don't need to specify == true
{ PermissionNeeded.Edit, u => u.Edit },
...
etc
};
And you would call it like this:
var clearance = Permissions[PermissionNeeded.Add](user);
or maybe
var clearance = Permissions[PermissionNeeded.Add](user) && Permissions[PermissionNeeded.Edit](user);
or perhaps
var clearance = Permission[PermissionNeeded.Add](user) || Permissions[PermissionNeeded.View](user);
and so on. Even if you don't have a user object, I think this would still be valid and make the code pretty easy to read, and if you have to modify your functions, its all in the dictionary...

Categories