Nullable Parameter used in Lambda Query is being ignored - c#

I'm trying to pass a null value from a RenderAction to another view. But in between, at the controller, my linq lambda expression is not loading the right field, despite the null value going through correctly..
SprintManager.cshtml
<div id="Global_Backlog_Board" class="Board_Panel">
#{Html.RenderAction("ListOfSingleCards", new
{
State_ID = 1
});}
</div>
HomeController.cs
public PartialViewResult ListOfSingleCards( int? Sprint_ID,
int State_ID = 1)
{
var Cards = db.Cards.Where(x => x.State_ID == State_ID &&
x.Sprint_ID == Sprint_ID &&
x.Deleted != 1 &&
x.Archive != 1).ToList();
return PartialView(Cards);
}
So Sprint_ID is being passed over and loaded as null here, but I can't get the query to load the rows correctly.
In fact, the following works:
var Cards = db.Cards.Where(x => x.State_ID == State_ID &&
x.Sprint_ID == null &&
x.Deleted != 1 &&
x.Archive != 1).ToList();
So I suppose I could check if Sprint_ID is null and depending on the result run one of the two seperate queries, but I'd like to understand why my original attempt is not working.
Thank you!

I don't know the correct answer but based on your solution you should be able to tidy it up:
var cards = new List<Card>();
var query = db.Cards.Where(x => x.State_ID == State_ID &&
x.Deleted != 1 &&
x.Archive != 1);
if (Sprint_ID.HasValue)
query = query.Where(x => x.Sprint_ID == Sprint_ID);
else
query = query.Where(x => x.Sprint_ID == null);
cards = query.ToList();

A nullable int won't return "null" in the way that you're thinking. You have to check the HasValue property of it to determine if there is a value, and if so then use it otherwise use null:
public PartialViewResult ListOfSingleCards( int? Sprint_ID,
int State_ID = 1)
{
var Cards = db.Cards.Where(x => x.State_ID == State_ID &&
x.Sprint_ID == Sprint_ID.HasValue ? Sprint_ID.Value : null &&
x.Deleted != 1 &&
x.Archive != 1).ToList();
return PartialView(Cards);
}

Until something better comes a long, I'm using this:
var Cards = new List<Card>();
if (Sprint_ID == null)
{
Cards = db.Cards.Where(x => x.State_ID == State_ID &&
x.Sprint_ID == null &&
x.Deleted != 1 &&
x.Archive != 1).ToList();
}
else
{
Cards = db.Cards.Where(x => x.State_ID == State_ID &&
x.Sprint_ID == Sprint_ID &&
x.Deleted != 1 &&
x.Archive != 1).ToList();
}

Related

Neglect variable from Query in entity framework where condition C#

public ActionResult sortFilteredItem(string sortByValue,string brand,string category,int price=0 )
{
var sortedData = (dynamic)null;
if (sortByValue != "")
{
if(sortByValue == "ltoh")
{
sortedData = DB.Prouducts.where(x=> x.brandName == brand & x.catName == category & x.price == price).ToList();
}
}
return View(sortedData);
}
how i can neglect if price=0 from query means that it does not make any impact on EF query because if price=0 the query does not returning expected output.Because i have not any record that has 0 price so the query is always returning null.
if(price != 0)
{
sortedData = DB.Prouducts.where(x=> x.brandName == brand & x.catName == category & x.price == price).ToList();
}
else
{
sortedData = DB.Prouducts.where(x=> x.brandName == brand & x.catName == category).ToList();
}
i have tried like this it is working good but that is lengthy process.if i have 4 or 5 more variable that,s optional so it is necessary to check null value first for working.Any recommendation ?
You can use the fllowing logic;
sortedData = DB.Prouducts.where(x=> x.brandName == brand
&& x.catName == category
&& (price == 0 || x.price == price)) //use this approach for every optional param
.ToList();
What you can do is apply filters only if the condition holds. Let's say you need to check catName and price. So:
var query = DB.Prouducts.Where(x=> x.brandName == brand);
if (category != null)
{
query = query.Where(x => x.catName == category);
}
if (price != 0)
{
query = query.Where(x => x.price == price)
}
sortedData = query.ToList();
Obviously you'll need one "if" per filter, but it is much better than considering all possible combinations.

EntityFremework: could a select before a where optimize this?

I'm trying to gain performance on this query, and I'd like to know if calling a Select() before the Where() I could have some improvement:
public async Task<List<PostValues>> GetValuesToTheDashboard(DataFilter filter, CancellationToken cancellationToken) {
long startTimestanp = Helpers.UnixTimeNow(filter.StartDate);
long endTimestanp = Helpers.UnixTimeNow(filter.EndDate);
return await
_context.CatchDetails.Where(
x => x.Monitoring.Client.Id == filter.CustomerId && x.Data.published >= startTimestanp
&& x.Data.published <= endTimestanp
&& ((filter.Sentiment == Sentiments.ALL) || x.Sentiment_enum == filter.Sentiment)
&& (filter.MonitoringId == 0 || x.Monitoring.id == filter.MonitoringId)
&& (filter.KeywordId == 0 || x.Keyword.Id == filter.KeywordId)
&& (filter.MotiveId == 0 || x.Motive.Id == filter.MotiveId)
&& (filter.SocialNetwork.Count == 0 || filter.SocialNetwork.Any(s => x.Data.social_media == s))
&& (filter.Busca == "" || x.Data.content_snippet.Contains(filter.Busca))
&& (filter.Gender.Count == 0 || filter.Gender.Any(g => x.Data.extra_author_attributes.gender_enum == g)))
.Select(s => new PostValues() {
CatchDetailsId=s.Id,
Monitoring=s.Monitoring.name,
Keyword=s.Keyword.Text,
Motive=s.Motive.Name,
Sentiment=s.Sentiment_enum,
Gender=s.Data.extra_author_attributes.gender_enum,
SocialMedia=s.Data.social_media,
Country=s.Data.extra_author_attributes.world_data.country_code,
State=s.Data.extra_author_attributes.world_data.region,
Published=s.Data.published
}).ToListAsync(cancellationToken);
}
There might be a way how to improve performance, but it won't be with switching Select and Where (as Chetan mentioned in the comment).
You could build the query in a sequence and based on the filter get a simpler query in the end. This would go like this:
var query = _context.CatchDetails.Where(
x => x.Monitoring.Client.Id == filter.CustomerId && x.Data.published >= startTimestanp
&& x.Data.published <= endTimestanp);
if (filter.Sentiment != Sentiments.ALL)
{
query = query.Where(x => x.Sentiment_enum == filter.Sentiment);
}
if (filter.MonitoringId != 0)
{
query = query.Where(x => x.Monitoring.id == filter.MonitoringId);
}
[...]
return await
query.Select(s => new PostValues() {
[...]
}).ToListAsync(cancellationToken);
Do not forget, the variable query is already on memory of the application when the SQL returns data. If there is many results it could throw memory exception.
I suggest that you limit the range of date on that search.

Linq expressions where empty string acts as wildcard

I'm trying to write a search function with about 10 inputs in my criteria, all of the inputs are nullable.
What I've come up with is below however if the input is null I'd like it to act as a wildcard.
For example if model = "" id like the search query to act like:
context.products.where(product => product.location == location && product.type == type).tolist();
I'm sure it can be done with a load of if statements however there must be better solution.
Any ideas?
public static List<product> Search(FormCollection formCollection)
{
var model = formCollection["model"];
var location = formCollection["location"];
var type = formCollection["type"];
var results = context.products.where(product => product.model == model && product.location == location && product.type == type).tolist();
return results;
}
Something like this:
var results = context.products
.where(product => (model == null || product.model == model)
&& (location == null || product.location == location)
&& (type == null || product.type == type)).tolist();

LINQ2SQL doesn't return row if checking with null

I have following LINQ2SQL Query:
var map =
dbContext.TCPDriverMappings.FirstOrDefault(
c => c.DriverFacilityId == tcpDms.FacilityId &&
c.DriverControlledParameterId == controlledParamId &&
c.DriverValue == value);
All the types are string.
In my DB i have a row, which must be returned by query.
When value="0", controlledParamId =null and FacilityId ="abc" this query returns null, but when i wrote following:
var test = dbContext.TCPDriverMappings.FirstOrDefault(
c => c.DriverFacilityId == "abc" &&
c.DriverControlledParameterId == null &&
c.DriverValue == "0");
test was not null
What am i doing wrong?
P.S. I also tried c.DriverControlledParameterId.Equals(controlledParamId) but it also doesn't work.
The problem is, that LINQ2SQL has a special handling for the expression c.DriverControlledParameterId == null. It is translated to the SQL DriverControlledParameterId IS NULL.
But c.DriverControlledParameterId = controlledParamId is translated to the SQL DriverControlledParameterId = :p1, even when controlledParamId is null. And in SQL DriverControlledParameterId = NULL is undefined and as such never TRUE.
How to fix: Handle the null case specifically:
TCPDriverMapping test;
if(controlledParamId == null)
test = dbContext.TCPDriverMappings.FirstOrDefault(
c => c.DriverFacilityId == "abc" &&
c.DriverControlledParameterId == null &&
c.DriverValue == "0");
else
test = dbContext.TCPDriverMappings.FirstOrDefault(
c => c.DriverFacilityId == "abc" &&
c.DriverControlledParameterId == controlledParamId &&
c.DriverValue == "0");
Or like this:
var test = dbContext.TCPDriverMappings.FirstOrDefault(
c => c.DriverFacilityId == "abc" &&
((controlledParamId == null &&
c.DriverControlledParameterId == null) ||
c.DriverControlledParameterId == controlledParamId) &&
c.DriverValue == "0");
Or like this:
IQueryable<TCPDriverMapping> query =
dbContext.TCPDriverMappings.Where(c => c.DriverFacilityId == "abc" &&
c.DriverValue == "0");
if(controlledParamId == null)
query = query.Where(c => c.DriverControlledParameterId == null);
else
query = query.Where(c => c.DriverControlledParameterId == controlledParamId);
var test = query.FirstOrDefault();
That third option is what I would use. In my opinion, this is the more readable than option 2 and has no repeated code like the first one.

LINQ to Entities: nullable datetime in where clause

I have a where clause that looks up child objects on an entity:
var Lookup = row.Offenses.Where(x => x.Desc == co.Desc && x.Action == co.Action && x.AppealYN == co.AppealYN && x.OffDate == co.OffDate).ToList();
Sometimes the co.OffDate can be null, which will cause an exception. Right now, the only way I can think of to get around that, is to use an if statement:
if (co.OffDate.HasValue)
{
var Lookup = row.Offenses.Where(x => x.Desc == co.Desc && x.Action == co.Action && x.AppealYN == co.AppealYN && x.OffDate == co.OffDate).ToList();
}
else
{
var Lookup = row.Offenses.Where(x => x.Desc == co.Desc && x.Action == co.Action && x.AppealYN == co.AppealYN).ToList();
}
Is there anyway I can re-write the linq query to accomplish what the if statement does? I still want to do a lookup, even if the co.OffDate is null.
You could insert a ternary into your Where filter:
var Lookup = row.Offenses
.Where(x =>
x.Desc == co.Desc
&& x.Action == co.Action
&& x.AppealYN == co.AppealYN
&& (co.OffDate.HasValue ? x.OffDate == co.OffDate : true)
).ToList();
I would rewrite it to be more readable (in my opinion):
var query = row.Offenses.Where(x => x.Desc == co.Desc
&& x.Action == co.Action
&& x.AppealYN == co.AppealYN)
if (co.OffenseDate.HasValue)
{
query = query.Where(x.OffDate == co.OffenseDate);
}
var Lookup = query.ToList();

Categories