How to select null values with LINQ to SQL and DbLinq? - c#

When I
bool? isApproved = null;
db.Table.Where(item => item.IsApproved == isApproved).Count();
the last line value is 0. But when I
db.Table.Where(item => item.IsApproved == null).Count();
the value is correct.
I'm using SQLite, DbLinq and DbMetal.

I have seen it done like this:
db.Table.Where(
item => item.IsApproved.HasValue == isApproved.HasValue &&
(!item.IsApproved.HasValue || item.IsApproved.Value==isApproved.Value )
).Count();

Well, I had this problem before, I remember that the problem is in converting the LINQ query to a SQL statement.
The second expression has an equal in SQL that:
Where IsAproved is null
but the first expression does not because it is a comparision between a value in the database with a C# nullable variable.
To solve it, I would suggest to try:
db.Table.Where(item => isApproved != null ? item.IsApproved == isApproved.Value
: item.IsApproved == null).Count();

See this post
You should use
db.Table.Where(item => item.IsApproved.Equals(isApproved)).Count();
Then you should contact Microsoft and let them know how terrible this behavior is.

I don't know about the performance hit, but it works
bool? isApproved = null;
db.Table.Where(item => item.IsApproved == isApproved ||
!(item.IsApproved.HasValue || isApproved.HasValue))
.Count();

Try :
db.Table.Where(item => item.IsApproved == isApproved.Value).Count();

Related

Return a value of 1 if linq query count returns zero

Looking for an alternative to writing the following query.
this.MaxExpoConsultTypes = expos.Any() ? expos.Max(e =>
Math.Max(e.ExpComments
.Where(c => c.CMT_CNSLT_TYP_CD != null && c.CMT_CNSLT_TYP_CD.Trim() != "" && c.CMT_CNSLT_TYP_CD.Trim() != "?")
.GroupBy(c => c.CMT_CNSLT_TYP_CD)
.Count(),1)) : 0;
The Math.Max function won't work because expos is an IQueryable and SQL will not be able to translate it, but is there to show how I want the results to return.
If the query returns a count of zero, I would like to reset it to 1.
How can I accomplish this?
Any() resolved your problem
this.MaxExpoConsultTypes = expos.Any() ? e.ExpComments
.Where(c => c.CMT_CNSLT_TYP_CD != null && c.CMT_CNSLT_TYP_CD.Trim() != "" && c.CMT_CNSLT_TYP_CD.Trim() != "?")
.GroupBy(c => c.CMT_CNSLT_TYP_CD)
.Count() : 1;
A direct answer to your question would probably be to use your query as a subquery and then perform a projection that turns all 0s into 1s.
However, there is no gain in making the query more complicated to be executed against the database. Semantically, you're trying to find the expo with the highest number of comments satisfying a predicate, but you treat no comments as one instead of zero. The only way this is going to affect the end result is if for all expos you get a count of zero (because you Max over all of them). Thus, you can simply do this:
if (!expos.Any())
{
this.MaxExpoConsultTypes = 0;
}
else
{
var maxCount = expos.Max(e =>
e.ExpComments
.Where(c => c.CMT_CNSLT_TYP_CD != null && c.CMT_CNSLT_TYP_CD.Trim() != "" && c.CMT_CNSLT_TYP_CD.Trim() != "?")
.GroupBy(c => c.CMT_CNSLT_TYP_CD)
.Count());
this.MaxExpoConsultTypes = maxCount != 0 ? maxCount : 1;
}

short circuting linq queries thowing null error

Ive been having some trouble trying to get this linq statement to work. I am setting up a search using linq queries. What i want to do is if a search is null or empty, have it ignore that part of the filtering. So what i have set up is many where clauses that short circuit the where clause like so:
tvContent.LoadContent(
Live.Ringtones
.Where(x => cbSeller.SelectedValue== null ||
x.Property.SellerID == (int)cbSeller.SelectedValue)
.Where(x => cbProperty.SelectedValue==null ||
x.PropertyID == (int)cbProperty.SelectedValue)
.Where(x => string.IsNullOrEmpty(tbContentID.Text) ||
x.RingtoneID == ContentID)
.Where(x => string.IsNullOrEmpty(tbContentName.Text) ||
x.RingtoneName == tbContentName.Text).ToList());
But when I do this I keep getting null reference issues.
cbProperty, is empty, and selectedValue does show up null when I debug, but it still says there's a null reference issue. What am I doing wrong?
Why are you putting an invariant into the where clauses?
var ringtones = Live.Ringtones;
if (cbSeller.SelectedValue!= null)
ringtones = ringtones.Where(x=> x.Property.SellerID
== (int)cbSeller.SelectedValue);
if (cbProperty.SelectedValue!= null)
ringtones = ringtones.Where(x=> x.PropertyID
== (int)cbProperty.SelectedValue);
if(!string.IsNullOrEmpty(tbContentID.Text))
ringtones.Where(x=> x.RingtoneID == ContentID)
if(!string.IsNullOrEmpty(tbContentName.Text) )
ringtones.Where(x => x.RingtoneName == tbContentName.Text)
tvContent.LoadContent(ringtones.ToList());

Avoiding null exception in EF that is thrown by your query

I have a query like this :
result =
firstIdeaRepository.FindBy(
i => i.FirstIdeaState == FirstIdeaState && i.Date >= start && i.Date <= end)
.AsEnumerable()
.Select(j => new RptListOfCompanyBasedOnFirstIdeaState()
{
Name =
companyRepository.FindBy(i => i.UserId == j.UserId)
.FirstOrDefault()
DateOfMeeting =
calenderRepository.ConvertToPersianToShow(
meetingReposiotry.FindBy(s => s.FirstIdeaId == j.Id)
.FirstOrDefault()
.Date),
DateOfExit =
calenderRepository.ConvertToPersianToShow(j.DateOfExit.Value),
ReasonOfExit = j.ReasonOfExit,
}).ToList();
return result;
As you can see i use FirstOrDefault() and j.DateOfExit.Value and sometimes my Date doesn't have any values or sometime my other variables are null too because i use firstordefaut() like
companyRepository.FindBy(i => i.UserId == j.UserId).FirstOrDefault().
So my query throws a null exception and the result can't be created ,how can i handle this exception and for example if the .NET detects the null value ignores it by default or uses a default values for that ?
Best regards.
I would make the following changes:
result =
firstIdeaRepository.FindBy(
i => i.FirstIdeaState == FirstIdeaState && i.Date >= start && i.Date <= end)
.AsEnumerable()
.Select(j => new RptListOfCompanyBasedOnFirstIdeaState()
{
Name =
companyRepository.FindBy(i => i.UserId == j.UserId)
.FirstOrDefault()
DateOfMeeting =
callenderRepository.ConvertToPersianToShow(
meetingReposiotry.FindBy(s => s.FirstIdeaId == j.Id)
// project a new sequence first, before calling `FirstOrDefault`:
.Select(s => s.Date)
.FirstOrDefault(),
DateOfExit =
j.DateOfExit.HasValue ?
callenderRepository.ConvertToPersianToShow(j.DateOfExit.Value) :
null,
ReasonOfExit = j.ReasonOfExit,
}).ToList();
When you use FirstOrDefault, there's a possibility that you'll get null back (in the case of reference types), and so you need to plan for that in your code.
For example, when assigning DateOfMeeting, you could project the results (using .Select) before using .FirstOrDefault, so that you're not ever accessing the Date property on what could be a null value.
As for DateOfExit, I've used the conditional operator to determine whether to call the calendarRepository's method at all. This assumes that DateOfExit is nullable.
Unrelated: "Calendar" is spelled with one "l" and not two.
Since you're using a nullable date, you can try filtering by values that have date, something like:
.FindBy(s => s.FirstIdeaId == j.Id && s.Date.HasValue)
This will ensure that you don't get any records with null date.
As I mentioned in comments, other cases need to be handled on case-by-case basis. Judging by the code you've shown, maybe you can handle Name as:
Name = companyRepository.FindBy(i => i.UserId == j.UserId).FirstOrDefault() ?? "anonymous";
and so on.
Another example:
If you do want to get the record even if DateOfMeeting is null, then add a check for HasValue in subsequent part or default it to some date:
DateOfExit = j.DateOfExit.HasValue ?
callenderRepository.ConvertToPersianToShow(j.DateOfExit.Value)
: (DateTime)null, // you need to make `DateOfExit` nullable and then handle that downstream
// or (default with current date)
DateOfExit = j.DateOfExit.HasValue ?
callenderRepository.ConvertToPersianToShow(j.DateOfExit.Value)
: callenderRepository.ConvertToPersianToShow(DateTime.Now),
// or (default with empty date)
DateOfExit = j.DateOfExit.HasValue ?
callenderRepository.ConvertToPersianToShow(j.DateOfExit.Value)
: callenderRepository.ConvertToPersianToShow(new DateTime()),
Moral of the story: figure out what the default value should be in case of null and then substitute that accordingly in the query when calling FirstOrDefault().
The broadest solution would be to use the idea of an null object with the DefaultIfEmpty<T>(T DefaultValue) method in your query. An example would be:
var defaultMeeting = new Meeting() { Date = new DateTime() };
var dateOfMeeting = meetingRepository.FindBy(s => s.FirstIdeaId == j.Id)
.DefaultIfEmpty(defaultMeeting)
.FirstOrDefault()
.Date;

How to check for null before I use in linq?

I have an list of objects that contains another object in it.
List<MyClass> myClass = new List<MyClass>();
I want to do some linq like this
myClass.Where(x => x.MyOtherObject.Name = "Name").ToList();
Thing is sometimes "MyOtherObject" is null. How do I check for this?
Simple, just add an AND clause to check if it's not null:
myClass.Where(x => x.MyOtherObject != null && x.MyOtherObject.Name = "Name").ToList();
As of C# 6, you can also use a null conditional operator ?.:
myClass.Where(x => x.MyOtherObject?.Name == "Name").ToList();
This will essentially resolve the Name property to null if MyOtherObject is null, which will fail the comparison with "Name".
Try it online
You can just make your predicate check for null...
myClass.Where(x => (x.MyOtherObject == null) ? false : x.MyOtherObject.Name == "Name").ToList();
I would do something like this:
myClass.Where(x => x.MyOtherObject != null)
.Where(y => y.MyOtherObject.Name = "Name")
.ToList();

LINQ Expression not evaluating correctly

I have the following LINQ expression that's not returning the appropriate response
var query = from quote in db.Quotes
where quote.QuoteStatus == "Estimating" || quote.QuoteStatus == "Rejected"
from emp in db.Employees
where emp.EmployeeID == quote.EmployeeID
orderby quote.QuoteID descending
select new
{
quote.QuoteID,
quote.DateDue,
Company = quote.Company.CompanyName,
Attachments = quote.Attachments.Count,
Employee = emp.FullName,
Estimator = (quote.EstimatorID != null && quote.EstimatorID != String.Empty)
? db.Employees.Single (c => c.EmployeeID == quote.EstimatorID).FullName
: "Unassigned",
Status = quote.QuoteStatus, Priority = quote.Priority
};
The problem lies in the Estimator = (quote.EstimatorID != null && quote.EstimatorID != String.Empty) ? db.Employees.Single(c => c.EmployeeID == quote.EstimatorID).FullName : "Unassigned" part.
I NEVER get it to evalueate to "Unassigned", on the ones that are supposed to, it just returns null. Have I written this wrong?
Try this and see if you're receiving the same values:
Estimator = ((!string.IsNullOrEmpty(quote.EstimatorID) && !string.IsNullOrEmpty(quote.EstimatorID.Trim())
? (db.Employees.Single(c => c.EmployeeID == quote.EstimatorID)).FullName
: "Unassigned")
If that doesn't work, try replacing the check in the ternary expression (!string.IsNullOrEmpty part) with false and see if you reach "Unassigned". I've found that sometimes, when you use a ternary expression in a LINQ query, you have to wrap the whole thing in parentheses.
I think your expression is correct, although I would advise changing it to !string.IsNullOrEmpty(quote.EstimatorID) for clarity.
Note however that your expression could still return null if db.Employees.Single(c => c.EmployeeID == quote.EstimatorID).FullName returns null.
Then it looks like quote.EstimatorID is not null or empty string. Is db.Employees.Single() returning null here? Debug it - put breakpoints into those parts of the expression (putting them on separate lines, if necessary). If you can't do that wrap methods around them that call Debug.WriteLine() or similar.

Categories