null vs default(decimal?) set to null - giving different results - c#

Using: Entity Framework 4.3.1, MVC 4
Sample database records (for example):
Id Height
1 null
2 2.1
Why does this first statement bring back zero results:
decimal? scannedItemHeight = default(decimal?);
(from st in Stocks
where st.Height == scannedItemHeight
select st.Id).ToList();
But this statement returns record Id 1:
(from st in Stocks
where st.Height == null
select st.Id).ToList();
If scannedItemHeight is null, I only want to match values where the height is null too.
I only want to return the first record, Id 1.
UPDATE
I ended up using:
st.Height == scannedItemHeight || (scannedItemHeight == null && st.Height == null)

That's because in first case database query would be something like
where Height = #param1 ...
While in second case that would be
where Height is null
First query would return no results because #param1 would be null and no row can match such condition.
Main point is that from C# standpoint those queries are equivalent, but from sql standpoint they are not: you should use IS NULL (or IS NOT NULL) in sql to check for nulls.
How to fix depends on what do you want to do when your parameter is null. In your case: use Jon Skeet's answer.
If someone will want to ignore parameter and not filter by it at all(quite common case, for example when parameter represents user's input in some field, and when nothing is typed there - nothing to filter), then do:
where scannedItemHeight == null || st.Height == scannedItemHeight
which will be in sql like
where #param1 is null OR Height = #param1

I've certainly seen some odd LINQ behaviour before now, due to the way that SQL handles nulls not being the same as the way that C# handles nulls. In C#, a == b is true if a and b are both null, whereas in SQL they're not... instead you have to deliberately check for nullity. I would try:
var temp = (from st in Stocks
where st.Height == scannedItemHeight || (scannedItemHeight == null && st.Height == null)
select st.Id).ToList();
Or construct the queries differently:
var filtered = scannedItemHeight == null
? Stocks.Where(st => st.Height == null)
: Stocks.Where(st => st.Height == scannedItemHeight);
var temp = filtered.Select(st => st.Id).ToList();

Related

Entity Framework 6 and is null

I would like to get all lines
from a table where column: CODEFIN (varchar) not like "MIR" or "CED".
My table looks like this:
CODEFIN
ID
NULL
2
NULL
3
MIR
2
My Entity Framwork linq request is:
db.MYTABLE.Where(m => m.CODEFIN !="MIR" && m.CODEFIN != "CED") [...]
But CODEFIN null lines not appear...
I get the generated sql, but this is the same things in my sql editor.
the sql is like this:
SELECT
[Extent1].[CODEFIN] AS [CODEFIN],
[Extent1].[ID] AS [ID],
FROM [dbo].[MYTABLE] AS [Extent1]
WHERE ('MIR' <> [Extent1].[CODEFIN] AND 'CED' <> [Extent1].[CODEFIN])
Thank you.
Sylvain
I would do it as
db.MYTABLE.Where(m => m.CODEFIN == NULL ||
(m.CODEFIN !="MIR" && m.CODEFIN != "CED"))
or use Contains:
db.MYTABLE.Where(m => m.CODEFIN == NULL ||
!(new [] {"MIR", "CED"}.Contains(m.CODEFIN)))
Which would yield the SQL:
WHERE [Extent1].[CODEFIN] IS NULL OR ([Extent1].[CODEFIN] NOT IN ('MIR', 'CED'))
Comparing something (even NULL) to NULL always yields NULL, not FALSE, and NOT(NULL) is still NULL, not TRUE, so you have to be more explicit about checking for nulls.
Add:
&& m.CODEFIN == null
A sometimes more efficient solution is to use Except
db.MYTABLE.Where(m => new [] {"MIR", "CED"}
.Except(new[] {m.CODEFIN})
.Any())
This should hopefully result in the following SQL
WHERE EXISTS (
SELECT 'MIR'
UNION
SELECT 'CED'
EXCEPT
SELECT [Extent1].[CODEFIN]
)
This is pretty efficient, as shown here.

Convert null integer into zero(0) in where clause using linq

i am getting data from user table using linq in this table i have two field AgencyID (int) and MemberID (int) in table these fields are null values when i am calling data by using below query it does not find any record although it exists, reason is that this part (Where(x.AgencyID== null && x.MemberID == null) have to be pass '0' instead of null how i convert it into zero
i have tried
return View(db.vt_Users.Where(x => x.IsDeleted != true &&
x.AgencyID == null &&
x.MemberID == null)
.ToList());

Linq to SQL issue with where clause

I am trying to create a where clause in Linq to SQL using the following logic
if #supplierid is null return all records.
if #supplierid is not null return where supplierid is equals to #supplierid.
and the one that is creating an issue:
if #supplierid ==0 return all records where supplierid is null
I tried writing this like
var answers =
from thisChargeableService in this.GetAll()
where
(
(
(supplierId == null) ||
(
((supplierId < 1) && (thisChargeableService.SupplierId == null)) ||
((supplierId != null) && (thisChargeableService.SupplierId == supplierId.Value))
)
));
This works with the first two conditions but when #supplierid = 0, nothing is returned.
Any help with this would be much appreciated
edit
Basically I have a dropdown of N/A with an id of 0. I have used this to identify that an option has been selected from dropdown and the user is targeting all rows where the supplier id is N/A.
The database contains no entries with 0 as the supplierid, so instead I am trying to target this with where the supplierid is null or the below in SQL
SELECT * FROM ChargeableService
WHERE
(#supplierid is null)
OR
(
(#supplierid is not null and supplierid = #supplierid) or
(#supplierid = 0 AND supplierid is null)
)
With Linq, there is no need to try to build one query to do all. Instead you can build your expression in buts and let deferred execution build and execute the correct sql.
So, this is the way I would do it.
var answers = this.GetAll().AsQueryable();
if (supplierId.HasValue && (supplierId.Value != 0))
answers = answers.Where(a=>a.SupplierId == supplierId.Value);
if (supplierId.HasValue && (supplierId.Value == 0))
answers = answers.Where(a=>!a.SupplierId.HasValue);
I've taken your query and run it against some similar data and the following works:
var answers =
from thisChargeableService in this.GetAll()
where
(
supplierId == null ||
(supplierId == 0 && thisChargeableService.SupplierId == null) ||
(supplierId > 0 && thisChargeableService.SupplierId == supplierId)
)
select thisChargeableService;

How do I translate this SQL query to Lambda or LINQ that uses (where is null)

I've been trying to modify some rows of data in SQL to test in my application and I've noticed my query in Lambda brings back 0 rows when I am expecting 2387 row. The source of the problem is I am using parenthesis in a WHERE clause in SQL to look at some null values. This is the SQL query:
SQL
-- THIS WORKS!
select * from vwAppsWithIssues
where fld1stCheckAllocatedTo = 'nicholasg' and fldStage = 1
and (fldStopStartDate is null or fldStopEndDate is not null)
-- The query was originally this (doesn't return rows)
select * from vwAppsWithIssues
where fld1stCheckAllocatedTo = 'nicholasg' and fldStage = 1
and (fldStopStartDate = null or fldStopEndDate <> null)
LAMBDA query that returns 0 rows
public static int GetApplicationsFirstCount(string UserId)
{
try
{
using (IME_CheckOffEntities IME_CheckOffEntities = new IME_CheckOffEntities())
{
return IME_CheckOffEntities.vwAppsWithIssues
.Where(a => a.fld1stCheckAllocatedTo == UserId && a.fldStage == 1 && (a.fldStopStartDate == null || a.fldStopEndDate != null))
.ToList().Count;
}
}
catch (Exception ex)
{
throw;
}
}
Update
Using LINQPad I have written this expression:
VwAppsWithIssues
.Where (v => v.Fld1stCheckAllocatedTo == "nicholasg"
&& v.FldStage == 1
&& (v.FldStopStartDate == null || v.FldStopEndDate != null)).Count()
that generates this sql
SELECT COUNT(*) AS [value]
FROM [vwAppsWithIssues] AS [t0]
WHERE ([t0].[fld1stCheckAllocatedTo] = #p0) AND ([t0].[fldStage] = #p1) AND (([t0].[fldStopStartDate] IS NULL) OR ([t0].[fldStopEndDate] IS NOT NULL))
So now that I have some lambda that I think will work, I simply copy it to visual studio.
var count = IME_CheckOffEntities.vwAppsWithIssues
.Where(v => v.fld1stCheckAllocatedTo == "nicholasg" && v.fldStage == 1 && (v.fldStopStartDate == null || v.fldStopEndDate != null)).Count();
It still returns only 0 rows?! I am passing in the right userId in C# as well.
My count in c# also returns 0 rows. Any idea how I can rewrite this C# query?
from linqpad, on one of my schema
from
f in Files
where
f.PubDate == null || f.FilingDate != null
select
f.IdFile
is translated as follow
SELECT
[Extent1].[idFichier] AS [idFichier]
FROM [dbo].[tableF] AS [Extent1]
WHERE ([Extent1].[datePubliF] IS NULL) OR ([Extent1].[dateDepotF] IS NOT NULL)
so, in your case, are you, for example, sure of the UserId value ?

LINQ with multiple left join and where clause

I have following query, and I am converting it to LINQ.
select acq.ACQPub as Prev_ACQPub
, ve.CompanyID
, ve.EntityID
, ve.RoundID
, ve.EntityName
, ve.Date
, ve.RoundTypeCode
, ve.EventType
, ve.PostValue_DJVS
, ve.PostVal
, ve.PreVal
, fin.FinanceStat
from ValuationEvents_PIT_New as ve
left join Acq_PublicDummy as acq
on ve.EntityID = acq.EntityID
left join FinStat_New as fin
on ve.EntityID = fin.EntityID
where ve.EventType in('ACQ','LBO')
and acq.ACQPub is null
I wanted to double check if I've done it right or there is a better way of doing it.
Here is my code:
return (from ve in valuationEvents where ve.EventType == EventTypes.Acq || ve.EventType == EventTypes.Lbo
join acq in acqPublicDummies on ve.EntityId equals acq.EntityID into veAcq
from x in veAcq.DefaultIfEmpty() where x != null && x.ACQPub == null
join fin in finStats on ve.EntityId equals fin.EntityID into veFin
from y in veFin.DefaultIfEmpty()
select new AcqResearch
{ PrevAcqPub = x == null ? null : x.ACQPub,
EntityId = ve.EntityId,
CompanyId = ve.CompanyId,
RoundId = ve.RoundId,
Date = ve.Date,
RoundTypeCode = ve.RoundTypeCode,
EventType = ve.EventType.ToString(),
PostValueDjvs = ve.PostMoneyValue,
PostVal = ve.PostVal,
PreVal = ve.PreVal,
FinanceStat = y == null ? null : y.FinanceStat
}).ToList();
Since result will be used > 1 times I am returning List instead of IEnumerable.
Also I can't run SQL and compare result of it with LINQ result, since query above runs against of Raw data and LINQ is running after data calculations and additional cleansing process. So there is no way for me to compare query result with my LINQ result. I just need to rely that logic is correct. What is the same is SQL logic and LINQ logic.
Thank you very much for your help and feedback!
If you want to verify that the query is the same, you can look at the SQL that is generated from the linq. there are a few ways of doing this:
Use SQL Profiler
Paste the query into LinqPad and view the SQL tab
Set the Log property on your datacontext
You can then compare the two SQL queries and check for differences.
As an aside, in your case the only things I would change are style related - I would move all of the where clauses to just above the select clause, so it is easier to see what filter you are applying. Also, the line
PrevAcqPub = x == null ? null : x.ACQPub
Seems like it may as well be
PrevAcqPub = null
Since you have already filtered out all x that are null and that have x.ACQPub != null (Same goes for the SQL query).
Your solution looks correct to me

Categories