I'm having a problem with a LINQ to SQL query, the data being returned from the server could be null so I've set up an if statement within the query but the query is still throwing an exception.
This is a shortened down version of the query code
var a = from b in db.branches
where (b.Location != null) ?
(
(Query.Location == null) ?
true :
//The following line causes the exception to be thrown
object.Equals(Query.Location.ToLower() , b.Location.ToLower())
) :
(
(Query.Location == null) ?
true :
false
)
select b;
If the search term "Location" is null then I don't want to filter by location, but if it isn't null then I have to check if the value in the row is null or not as some of entries have a null location.
The code works fine until I add in the compare line. In order to get to the compare line, both Query.Location and b.Location cannot be null therefore the code shouldn't fail.
Any idea what the problem could be?
Thanks.
EDIT
If i remove the .toLower() from the object.equals call then the query runs correctly, it also manages to work no matter what case the query is in.
var a = from b in db.branches
where (b.Location != null) ?
(
(Query.Location == null) ?
true :
//The following line causes the exception to be thrown
object.Equals(Query.Location , b.Location)
) :
(
(Query.Location == null) ?
true :
false
)
select b;
I wouldn't like to say for sure what's going wrong here, but I think you could actually make your code significantly simpler by splitting it into two different queries:
public void Search(SearchTerms Query)
{
var queryWithLocation = db.branches.Where(b =>
Query.Location.Equals(b.Location, StringComparison.OrdinalIgnoreCase);
var query = Query.Location != null ? queryWithLocation : db.branches;
}
I've changed the way of doing the Equals - that's the way I prefer to perform case-insensitive searches; you'll have to see whether it works for LINQ to SQL.
Try this;
public void Search(SearchTerms Query)
{
var a = from b in db.branches
where (b.Location != null) ?
(
(Query.Location == null) ?
true
:
//The following line causes the exception to be thrown
Query.Location.ToLower() == b.Location.ToLower()
)
:
(
(Query.Location == null) ?
true
:
false
)
select b
}
I believe the object is probably causing the NullReference
from b in db.branches
let location = b.Location
where location != null ?
b.Location.Equals(b.Location, Query.Location ?? b.Location, StringComparison.OrdinalIgnoreCase) : // if Query.Location is null then select all
false // to select nothing in this case
select b;
Related
I am working with the following Entity Framework query. I know there's a lot going on here but am hoping it's clear enough that someone might be able to spot the issue.
var lineItems = from li in Repository.Query<CostingLineItem>()
let cid = (li.ParentCostingPackage != null) ?
li.ParentCostingPackage.ParentCostingEvent.ProposalSection.Proposal.Costing.Id :
li.ParentCostingEvent.ProposalSection.Proposal.Costing.Id
where cid == costingId &&
li.OriginalProductId.HasValue &&
(li.Quantity.HasValue && li.Quantity.Value > 0) && // li.QuantityUnitMultiplier
Classifications.Contains(li.OriginalProduct.ClassificationEnumIndex)
let selectedChoiceId = li.OriginalPackageOptionId.HasValue ?
(from c in li.OriginalPackageOption.CostingLineItems
orderby (c.IsIncluded ?? false) ? -2 : (c.IsDefaultItem ?? false) ? -1 : c.Id
select (int)c.OriginalPackageOptionChoiceId).FirstOrDefault() :
0
where selectedChoiceId == 0 || (li.OriginalPackageOptionChoiceId.HasValue && li.OriginalPackageOptionId.Value == selectedChoiceId)
let hasProviderAvailable = li.OriginalProductItem.ProductItemVendors.Any(
piv => piv.ProductPricings.Any(pp => pp.ProductItemVendor.CompanyId != null || pp.ProductItemVendor.HotelId != null))
select new
{
LineItem = li,
ProductItem = li.OriginalProductItem,
Product = li.OriginalProduct,
Vendors = li.CostingLineItemVendors,
HasProviderAvailable = hasProviderAvailable
};
As is, this query generates the following run-time error:
The wait operation timed out
If I change the section that declares selectedChoiceId to the following, the error goes away:
let selectedChoiceId = 0
Can anyone see how that code is consistently causing a time-out error?
(Note: This code is part of a large application that has been running for several years. So I really don't think this has anything to do with the connection string or anything like that. If I make the change above, it works consistently.)
The query can be simplified in a number of ways, which should make it easier to optimize by the database engine.
Firstly, you can remove a number of null checks (HasValue), because they're not relevant in SQL, but they do bloat the generated SQL.
Secondly, I think this check involving selectedChoiceId can be greatly simplified. This is what I think the statement could look like:
from li in Repository.Query<CostingLineItem>()
let cid = (li.ParentCostingPackage != null) ?
li.ParentCostingPackage.ParentCostingEvent.ProposalSection.Proposal.Costing.Id :
li.ParentCostingEvent.ProposalSection.Proposal.Costing.Id
where cid == costingId &&
li.OriginalProductId.HasValue &&
li.Quantity > 0 && // no null check
Classifications.Contains(li.OriginalProduct.ClassificationEnumIndex)
let selectedChoiceId = (from c in li.OriginalPackageOption.CostingLineItems
orderby c.IsIncluded ? -2 : c.IsDefaultItem ? -1 : c.Id // no null checks
select (int)c.OriginalPackageOptionChoiceId).FirstOrDefault()
where !li.OriginalPackageOptionId.HasValue || li.OriginalPackageOptionId == selectedChoiceId
let hasProviderAvailable = li.OriginalProductItem.ProductItemVendors.Any(
piv => piv.ProductPricings.Any(pp => pp.ProductItemVendor.CompanyId != null || pp.ProductItemVendor.HotelId != null))
select new
{
LineItem = li,
ProductItem = li.OriginalProductItem,
Product = li.OriginalProduct,
Vendors = li.CostingLineItemVendors,
HasProviderAvailable = hasProviderAvailable
}
For the rest, of course there are the usual suspects. Better indexes may become more important as the database volume increases. Checking for (and fixing) database fragmentation can also have a significant impact.
I think this will give you a better performance but not sure if it'll fix the problem :
let selectedChoiceId = li.OriginalPackageOptionId.HasValue
? (from c in li.OriginalPackageOption.CostingLineItems
let cOrder = (c.IsIncluded ?? false) ? -2 : (c.IsDefaultItem ?? false) ? -1 : c.Id
orderby cOrder
select (int) c.OriginalPackageOptionChoiceId).FirstOrDefault()
: 0
I run this query And if The Query is return with empty values the programme is crashed.
var cust = db.Customers.FirstOrDefault(x => x.telephone == txtTel.Text);
if (cust.BlackList == 1)
{
MessageBox.Show("This customer is blacklisted, Do you wish to continue with this job?");
}
Please Suggest me Some Efficient solution
Thanks.
You are getting a null pointer because FirstOrDefault returns the default value of the object if the result is not found (in this case it is null):
var cust = db.Customers.FirstOrDefault(x => x.telephone == txtTel.Text);
if (cust != null && cust.BlackList == 1)
{
MessageBox.Show("This customer is blacklisted, Do you wish to continue with this job?");
}
You need to check for null because that's what FirstOrDefault returns if there is no record that satisfies your condition:
if(cust != null && cust.BlackList == 1)
FirstOrDefault will return a default value if there is no element in the list which satisfy the condition, in this case it will be null. As you call a property on the null value it will naturally cause an exception.
You should check if cust is null, like:
if(cust != null && cust.BlackList == 1)
Of course you can display another message if the user doesn't exist based on the logic of your application.
i have written below query in LINQ to perform left join but its throwing error:
var qry = from c in dc.category_feature_Name_trans_SelectAll_Active()
join p in dc.product_category_feature_trans_SelectAll()
on c.cft_id equals p.cft_id into cp
from p in cp.DefaultIfEmpty()
select new
{
c.cft_id,
c.feature_id,
c.feature_name,
p.product_id ,
p.value
};
Error:
Object reference not set to an instance of an object.
Description: An unhandled exception occurred during the execution of the
current web request. Please review the stack trace for more information about
the error and where it originated in the code.
Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.
Source Error:
Line 57: on c.cft_id equals p.cft_id into cp
Line 58: from p in cp.DefaultIfEmpty()
error Line 59: select new
Line 60: {
Line 61: c.cft_id,
Please help me.
cp.DefaultIfEmpty() returns a sequence which will have a single null value in if cp was empty.
That means you have to account for the fact that the p in
from p in cp.DefaultIfEmpty()
may be null. Now, you haven't really said what you want to happen in that case. You might want something like this:
var qry = from c in dc.category_feature_Name_trans_SelectAll_Active()
join p in dc.product_category_feature_trans_SelectAll()
on c.cft_id equals p.cft_id into cp
from p in cp.DefaultIfEmpty()
select new
{
c.cft_id,
c.feature_id,
c.feature_name,
product_id = p == null ? null : p.product_id,
value = p == null ? null : p.value
};
... or you may want some different handling. We don't know the types of p.product_id or p.value, which doesn't help. (For example, you'll need a bit more work with the above code if product_id is a value type.)
You are making left join, so p can be null. You need to account for that.
Here is the query that should work, although I don't know for sure what kind of value is p.value. The query will work if value is a reference type. If value is value type, than use the cast similar to product_id cast.
var qry = from c in dc.category_feature_Name_trans_SelectAll_Active()
join p in dc.product_category_feature_trans_SelectAll()
on c.cft_id equals p.cft_id into cp
from p in cp.DefaultIfEmpty()
select new
{
c.cft_id,
c.feature_id,
c.feature_name,
product_id = p == null ? (int?)null : p.product_id,
value = p == null ? null : p.value,
};
I am facing the same issue while using the LEFT JOIN to multiple tables in LINQ query and I was facing null reference exception. I used the trick to check the null value using the "?" Please correct me if my approach is incorrect.
var deviceResultDetails = from pa in programAliasrecords
join pgm in Newprogramrecords on pa.program_id equals pgm.id into pgm_join
from pgm2 in pgm_join.DefaultIfEmpty()
join latest_fw in firmwareWithIdrecords on pgm2?.latest_firmware_id equals latest_fw?.id into latest_fw_join
from latest_fw2 in latest_fw_join.DefaultIfEmpty()
join dev_fw in firmwareWithIdrecords on pgm2?.firmware_group_id equals dev_fw?.firmware_group_id into dev_fw_join
from dev_fw2 in dev_fw_join.DefaultIfEmpty()
join vv in vulnerabilityrecords on pgm2?.id equals vv?.program_id into vv_join
from vv2 in vv_join.DefaultIfEmpty()
where
dev_fw2?.version == row.firmware
&& pa?.keyword == row.model
select new _deviceResults
{
model = row.model,
serial = row.serial,
firmware = row.firmware,
firmware_date = dev_fw2.br_date == null ? null: dev_fw2.br_date,
latest_firmware = latest_fw2.version == null ? null : latest_fw2.version,
latest_firmware_date = latest_fw2.br_date == null ? null : latest_fw2.br_date,
status = Convert.ToInt32(vulnerability_count) > 0 && pgm2.out_of_support == "TRUE" ? "Vulnerable (End of Suport)" :
Convert.ToInt32(vulnerability_count) > 0 && pgm2.out_of_support == " " ? "Vulnerable (Upgradeable)" :
pgm2.out_of_support == "TRUE" ? "Out-of-support" :
Convert.ToInt32(dev_fw2.revs_out_of_date) > 1 ? "Out-of-date" :
pgm2.id == "NonHP" ? "NonHP" :
pgm2.id == "NoFirmware" ? "No Firmware" :
pgm2.id == "HPink" || pgm2?.id == "HPOther" ? "Not evaluated (model not included yet)" :
pgm2.id == " " ? "Not evaluated (model not recognized)" :
dev_fw2.version == " " ? "Not evaluated (firmware version missing)" :
dev_fw2.id == " " ? "Not evaluated (firmware version mismatch)" : // && dev_fw.id in (select version from firmware)
dev_fw2.id == " " ? "Not evaluated (firmware version unrecognized)" :
dev_fw2.br_date == " " || pgm2.id == " " || dev_fw2.revs_out_of_date == " " ? "Not evaluated" : "OK",
out_of_support = pgm2.out_of_support == "" ? "false" : pgm2.out_of_support,
revs_out_of_date = dev_fw2.revs_out_of_date == null ? null : dev_fw2.revs_out_of_date,
program_id = pgm2.id == null ? null : pgm2.id,
firmware_id = dev_fw2.id == null ? null : latest_fw2.br_date
};
Use your Model Class as a parameter for DefaultIfEmpty() function.
from p in cp.DefaultIfEmpty(new yourModelClass())
First, Thomas Levesque had a good solution for ordering fields in a related table where the relation may not always be there:
userQuery = userQuery.OrderBy(u =>
(u.Department != null) ? u.Department.Name : String.Empty);
I need to do the same thing. My aggregate root is enormous:
myQuery = myQuery.OrderBy(p =>
(p.Seconds == null
? 0
: p.Seconds.FirstOrDefault() == null
? 0
: p.Seconds.First().Thirds == null
? 0
: p.Seconds.First().Thirds.FirstOrDefault() == null
? 0
: p.Seconds.First().Thirds.First().Forths == null
? 0
: p.Seconds.First().Thirds.First().Forths.FirstOrDefault() == null
? 0
: p.Seconds.First().Thirds.First().Forths.First().myField));
Is this really the way to do this, or is there something much easier to read? My other problem is that the nested myField has a matching "default" value sitting in the top level Query, also named by myField. The idea was to Order by the coalesce of these two fields (??).
Edit: I think this would include the "default value" from the first field:
myQuery = myQuery.OrderBy(p =>
(p.Seconds == null
? p.myDefaultField // Used to be zero
: p.Seconds.FirstOrDefault() == null
? p.myDefaultField
: p.Seconds.First().Thirds == null
? p.myDefaultField
: p.Seconds.First().Thirds.FirstOrDefault() == null
? p.myDefaultField
: p.Seconds.First().Thirds.First().Forths == null
? p.myDefaultField
: p.Seconds.First().Thirds.First().Forths.FirstOrDefault() == null
? p.myDefaultField
: p.Seconds.First().Thirds.First().Forths.First().myField));
How could I rewrite this OrderBy to be cleaner? This code fails with an error of "Cannot compare elements of type 'System.Collections.Generic.IEnumerable`1'. Only primitive types (such as Int32, String, and Guid) and entity types are supported."
I think you have a pretty nasty code smell going on here, but working with what you have got I wouldn't handle this in a LINQ query like that. Just for the sake of readability I'd do something like
myQuery = myQuery.OrderBy(p =>
(p.HasValidFields()
? p.Seconds.First().Thirds.First().Forths.First().myField
: p.myDefaultField
));
And inside of p's class
private bool HasValidFields
{
get
{
return p.Seconds != null &&
p.Seconds.FirstOrDefault() != null &&
.... ;
}
}
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.