Conditional OR has no effect in Linq-to-entities? - c#

I stumbled across a null ref exception today in one of my Linq-To-Entitites queries and wondered how that could be possible. It seems an conditional OR used as an OR-gate has no effect in Linq-To-Entities. A simplified example of my query is this:
from a in db.Articles
where a.Author == "John Doe"
&& (tag == null || a.Tags.Any(t => t.TagName == tag.TagName))
select a;
Now when tag is NULL, the right side of the where query still gets executed and a NULL reference exception occurs on tag.TagName. Maybe this is because Linq-To-Entities always translates the complete statement into SQL?
Anyhow ... how to get around this issue?
Thanks very much :)

var query = db.Articles.Where(x => x.Author == "John Doe");
query = tag == null
? query
: query.Where(x => x.TagName == tag.TagName);
or:
var query = from a in db.Articles
where a.Author == "John Doe"
select a;
query = tag == null
? query
: from a in query
where a.Tags.Any(t => t.TagName == tag.TagName)
select a;
Personally, I find the first one cleaner

Think about sql. Linq converts your code as a whole into sql query passing 'outside' objects as parameters and evaluating them. That's why it fails on evaluation of your null object.
It's a good practice to construct a linq query bit by bit based on conditions to reduce number of unnecessary code in resulted query, so it's better to split your query:
var query = db.Articles.Where(x => x.Author == "John Doe");
if( tag != null)
query = query.Where(x => x.TagName == tag.TagName);
Because your query will be evaluated and executed on selection you are welcome to add more conditions without worrying about multiple requests.

Related

How to use OR operator in Linq

I want to use OR function in my linq query.
Ex:
Sql:
select * from tblusers where userid=1 and status='a' or status='b';
Linq:
var result= _Repository.selectAll().where(x=>x.UserID==1 && x.status=="a" OR x.status=="B");
It's does work for linq query. so does anyone have any idea?
So you are aware about the && operator for comparison, then why not make a try with || operator? Anyway here is the solution for your problem, Following code will get you the result with UserID is 1 and status is either a or B.
_Repository.selectAll().where(x=>x.UserID==1 && (x.status=="a" || x.status=="B"));
Create an array of status you want to check and then use contains. something like this.
var statusList = new[] {"a", "b"};
.Where(x=> x.UserID == 1 && statusList.Contains(x.status));
Adding my 2 cents in here, there is another way you can write your sql query in C# which more or less resembles the sql syntax.
var result = from x in _Repository.SelectAll() where x.UserID == 1 && (x.Status == "a" || x.Status == "B") select x;
This syntax is Query Syntax/Expression where as your snippet is Method Syntax/Expression. Both will achieve same results. Also behind the scene, query syntax is compiled to Method syntax.
At compile time, query expressions are converted to Standard Query Operator method calls according to the rules set forth in the C# specification. Any query that can be expressed by using query syntax can also be expressed by using method syntax. However, in most cases query syntax is more readable and concise.
Or other approach with List.Contains, which generates sql query like
SELECT * FROM tblusers WHERE userid=1 AND status IN ('a','b');
var acceptedStatus = new List<string> { 'a', 'b' };
var result= _Repository.selectAll()
.Where(x => x.UserID == 1)
.Where(x => acceptedStatus.Contains(x.Status));
Notice that instead of && operator you can use another Where function and chain them. Can be more readable then fit all conditions in one line.
Try code:
var result =( from x in _Repository.selectAll()
where x.UserID==1 && (x.status=="a" || x.status=="B") select x);
another Solution
var result =( from x in _Repository.selectAll().where(c=>c.status=="a" || x.status=="B")
where x.UserID==1 select x);

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

Querying using NULL on varchar column

How do I pass null as a value to a string (varchar) column from linq to sql? I'm trying to query the table where some rows have NULL for a column (say, Col_A) and others have "NotNull" (string) as value.
string s = null;
var query = (from r in context.Table1
where r.Col_A == s
select r).ToList();
This returns 0 rows. But if I set s to "NotNull", I get the rows back as expected.
Any pointers will be helpful.
There is an annoying bug, where the following can work differently in some cases:
where x.Foo == null
vs
where x.Foo == s
where s happens to be null at execution. Basically, in some use-cases, it can incorrectly end up using:
WHERE [x].[Foo] = #p3
with #p3 a null value, but clearly that is not sensible in ANSI compliant SQL.
I would suggest if you are doing a test where the parameter value might be null, special-case it and code the query with a literal null in the C#. I did have some code that would use an expression-visitor to apply this after-the-fact, but it is easier just to special-case null. So:
var query = // some core query
if(s == null) { query = query.Where(x => x.Foo == null); }
else { query = query.Where(x => x.Foo == s); }
have you tried DBNull.Value? That's .net's DB equivalent to null.

C# SQL To Linq - Where Clause with multiple variables Comparison (var1+var2) !=(var1+var2)

I have these working in sql for large data set working great. However I'm having hard time converting to linq-I'm new to linq
Select * from table1 t1, table2 t2 where (t1.RoleId+t1.UserId)!=(t2.RoleId+t2.UserId).
On a side note, when the two variables are separated, I get undesired results.
Meaning the following: where (t1.RoleId != t2.RoleId && t1.UserId != t2.UserId)
In c# I have two anonymous lists. The last linq statement works great till nulls come into the picture. Nothing returns. I even thought of using a left join with no success.
So how would you tackle the above query with anonymous type lists?
Linq statments I have so far
var roleUserList =
(
from rls in roleResouceList
join user in userResourceList
on rls.FullResource.ToUpper() equals user.FullResource.ToUpper()
orderby rls.RoleID, user.UserID, rls.Res1, rls.Res2, rls.Res3
select new
{
RoleID = rls.RoleID,
UserID = user.UserID,
ServerId = rls.ServerID,
FullResource = rls.FullResource,
RlsRes1 = rls.Res1,
RlsRes2 = rls.Res2,
RlsRes3 = rls.Res3
}).Distinct().ToList();
var missingRoleUserList =
(
from rls in rlsCount
join usr in usrCount
on rls.Res1 equals usr.Res1
where rls.Total > usr.Total
select new
{
UserID = usr.UsrID,
RoleID = rls.RoleID
}).Distinct().ToList();
List<string> outputRoleUserList =
(
from rls in roleUserList
from mis in missingRoleUserList
where (rls.RoleID + rls.UserID) != (mis.RoleID +mis.UserID)
select rls.UserID + ",\"" + rls.RoleID
).DefaultIfEmpty().Distinct().ToList();
I'm not entirely certain that this is what you're looking for, but I'm going to give it a shot:
Try chaining your where clauses in Linq to SQL, and you may get a better result:
List<string> outputRoleUserList =
from rls in roleUserList
from mis in missingRoleUserList
where rls.RoleID != mis.RoleID
where rls.UserID != mis.UserID
select rls.UserID + ",\"" + rls.RoleID
This will actually generate SQL as follows:
rls.RoleId != mis.UserID AND rls.UserId != mis.UserID
However, you have already forced execution on roleUserList and missingRoleUserList, so what you're using in the third Linq statement is not really Linq to SQL but rather Linq to Objects, if I'm reading this correctly.
I'd be curious to see some additional information or clarification and then maybe I'll understand better what's going on!
EDIT: I realized another possibility, it's possible that the object.UserID or object.RoleID is throwing an internal NullPointerException and failing out because one of those values came back null. You could possibly solve this with the following:
List<string> outputRoleUserLIst2=roleUserList
.Where(x => x != null && x.UserID != null && x.RoleID != null && missingRoleUserList
.Where(y => y != null && y.UserID != null && y.RoleID != null && y.RoleID!=x.RoleID && y.UserID!=x.UserID)
.FirstOrDefault()!=null)
.Select(x => x.UserID + ",\"" + x.RoleID).Distinct().ToList();
This is not pretty, and this is the other Linq syntax (with which I am more comfortable) but hopefully you understand what I am going for here. I'd be curious to know what would happen if you dropped this into your program (If I've guessed all of your meanings correctly!). I'll look back in a bit to see if you have added any information!

Using multiple .Where() calls or && conditions for LinqToEntities queries

Are the following two queries equivalent? If they are not equivalent, which performs better? Is there a way I can see the sql output of the queries?
var query1 = items.Where(i => i.Enabled == true).Where(i => i.Name == "Bob");
var query2 = items.Where(i => i.Enabled == true && i.Name == "Bob");
As Andrew says, the two options are equivalent. One practically useful difference is that you can easily generate conditions in the Where clause programmatically. For example if you wanted to exclude certain names:
var query = items;
for(string name in excluded)
query = query.Where(i => i.Name != excluded);
This is something that cannot be done easily when writing query using && operator.
Both queries will translate to the same SQL - you can use a tool like LinqPad to verify this if you want (I just did). The LINQ provider that translate your expression trees into T-SQL is smart enough to understand that these queries are synonymous. Of course this means that both queries will perform equally as well.

Categories