List.contains throwing null exception? - c#

I have a join query like
public ActionResult Import(int[] userValue, int[] provalue, DateTime? StartDate, DateTime? EndDate)
{
List<int> actallid = db.Activitys.Select(x=>x.ID).ToList();
List<int> actchild = FileOperation.ChildActivity(actallid);
DateTime Start_Date = Convert.ToDateTime(StartDate);
DateTime End_Date = Convert.ToDateTime(EndDate);
IEnumerable<ViewModelActivitySearch> search = from r in db.Reports
join a in db.Activitys on r.ID equals a.Report_ID
join u in db.Users on r.Users_ID equals u.ID
join p in db.Projects on a.Projects_ID equals p.ID
join act in db.ActivityTypes on a.Activity_Type_ID equals act.ID
where (
(r.Start_Date == StartDate || r.End_Date == EndDate || userValue.Contains((int)r.Users_ID) || provalue.Contains((int)a.Projects_ID))
&&
//status is submitted=2, approved=3,exclude child activities
(!actchild.Contains((int)a.ID))
&&
(r.Status == 2 || r.Status == 3)
)
select new ViewModelActivitySearch
{
Id = a.ID,
Activity_Text = a.Activity_Text,
Deliverable = a.Deliverable,
Employee = string.Concat(u.FirstName, " ", u.LastName),
Start_Date = r.Start_Date,
End_Date = r.End_Date,
Activity_Date = a.Activity_Date,
Project = p.Name,
category = act.Activity_Type
};
BindProjectAndUser();
return View(search.ToList());
}
I have a search page where the user can enter a start date,enddate,choose users and choose projects.
I then made a join query to fetch all the data according to that variables.
The problem is when the user doesnot choose any user or project
the code
userValue.Contains((int)r.Users_ID) || provalue.Contains((int)a.Projects_ID))
gives the error
Unable to create a null constant value of type 'System.Int32[]'. Only entity types, enumeration types or primitive types are supported in this context.
What else can I use instead of contains so that this error does not arises.
Thanks

Check for null in values that you try to cast explicitly to int (like r.Users_ID) with ternary operator before using Contains:
where (r.Start_Date == StartDate || r.End_Date == EndDate ||
r.Users_ID != null? userValue.Contains((int)r.Users_ID) : false ||
a.Projects_ID != null ?provalue.Contains((int)a.Projects_ID) : false)
Method Contains() is a method to check if there's a certain value in a list of values of same type and it's perfectly fine to use it here.

Always do server-side validation!
Especially if you're using the users input for a SQL statement it's very important to validate it (sql injection)!
Simplest way: if-statements
if(userinput == null){
return View();
}
Note: If you are using Convert.ToDateTime(), you won't get an exception if the provided DateTime is null. You'll get the DateTime.MinValue and this could end in unexpected results.

Related

how to convert string to datetime in Linq where clause

DateTime newDate = DateTime.Now.AddDays(-30);
var queryResultPage = (from r in CustomPlanning
where (r.Assignment == "In Use") &&
(r.CUST_SHRT_NM != null) &&
System.Convert.ToDateTime(r.lastlogontimestamp) < newDate &&
!(from uA in SurveyActivity
where uA.CustomDemandID == r.ID
select uA.CustomDemandID).Contains(r.ID)
select r)
.OrderBy(t => t.ID);
Above is my code. lastlogontimestamp is a string field in my table. i need to do this check to show the query result in a grid. Can someone please help?
ok i tried this and it worked
DateTime newDate = DateTime.Now.AddDays(-30);
var queryResultPage = (from r in CustomPlanning
where (r.Assignment == "In Use") && (r.lastlogontimestamp != null && r.lastlogontimestamp != string.Empty)
&& (r.CUST_SHRT_NM != null)
&& !(from uA in SurveyActivity where uA.CustomDemandID == r.ID select uA.CustomDemandID).Contains(r.ID)
select r).OrderBy(t => t.ID).ToList();
queryResultPage = queryResultPage.Where(r => System.Convert.ToDateTime(r.lastlogontimestamp) < newDate).ToList();
You cannot in this query directly. You need to materialize the results from the query in a list, and run another query to filter the returned CustomPlanning with Linq-To-Objects (it supports conversion).
You can convert newDate to string
string newDate = DateTime.Now.AddDays(-30).ToString();
and try to compare strings instead, but you need to cover lots and lots of cases, so it is not recommended. You can consider changing the type of lastlogontimestamp to DateTime, when you have dates, it is natural to store them as dates.

asp.net/C#: Handle datetime if null using LINQ

I have null values in database specifically for Good Expiry Date, which is the field is:good_expiryDate.
What i want is to handle it in this way:
If good_expiryDate is null i want to present it as "" or "-", if it has value it will show the value retrieved from database?
the LINQ query i write is like this, but it return MinValue if good_expiryDate is null(this is what i tried to do).
var query = (from cd in db.CDIndexes
join gds in db.Goods on cd.cdin_CDIndexID equals gds.good_CDIndexId
join itms in db.Items on gds.good_ItemsID equals itms.item_ItemsID
where
cd.cdin_CompanyId==c.Comp_CompanyId&&
(
gds.good_RemainCBM > 0 ||
gds.good_RemainWT > 0 ||
gds.good_RemainPackages > 0 ||
gds.good_RemainVolumeWT > 0
)
&&
itms.item_ItemsID==customerId
select new DataItem
{
depNumber=(int)cd.cdin_Serial,
ItemDesc=gds.good_Name,
gdExpiryDate =(DateTime) gds.good_expiryDate==null?DateTime.MinValue: (DateTime)gds.good_expiryDate,
InvoicBalanceUnits = (decimal) gds.good_RemainPackages,
WTBal=(decimal)gds.good_RemainWT,
VolWT=(decimal)gds.good_RemainVolumeWT
}
);
return query.ToList();
Update: good_expiryDate is type of Datetime, nullable in database
Ensure that gdExpiryDate is of type string.
Then change this line
gdExpiryDate =(DateTime) gds.good_expiryDate==null?DateTime.MinValue: (DateTime)gds.good_expiryDate,
to
gdExpiryDate = gds.good_expiryDate==null? "-" : ((DateTime)gds.good_expiryDate).ToString(),
Change gdExpiryDate type to string type and write like this:
select new DataItem
{
depNumber=(int)cd.cdin_Serial,
ItemDesc=gds.good_Name,
gdExpiryDate = gds.good_expiryDate == null ? "" : gds.good_expiryDate.Value.ToString("dd.mm.yyyy"),
InvoicBalanceUnits = (decimal) gds.good_RemainPackages,
WTBal=(decimal)gds.good_RemainWT,
VolWT=(decimal)gds.good_RemainVolumeWT
}

Null value in the result of a left outer join linq causes error

I have linq query, that left outer join two tables. I found if a value of a field returns null,, then I will get an error message:
"The cast to value type 'System.Int32' failed because the materialized value is null. Either the result type's generic parameter or the query must use a nullable type."
I copied my linq below:
var SrvRef = from s in db.SrvHeads
join r in db.Referrants on s.svhReferrer equals r.refID into r_join
from r in r_join.DefaultIfEmpty()
where s.svhAccID == accId &&
s.svhHeadCnt == HeadId
select new
{
s.svhBalance,
r.refID
};
bool FBeenPaid = SrvRef.FirstOrDefault().svhBalance == 0M; //this causes error
How can I fix this problem?
I'm slightly surprised at the kind of error you're getting, but there are two places you need to take account of the possibility of the result being null:
Within the query, where r can be null. (If you don't want to match when there are no elements in r_join matching s, you shouldn't be using a left outer join)
In the result itself: you're using FirstOrDefault() which will return null if SrvRef is empty.
So at first glance it should probably be something like:
var query = from s in db.SrvHeads
join r in db.Referrants on s.svhReferrer equals r.refID into r_join
from r in r_join.DefaultIfEmpty()
where s.svhAccID == accId && s.svhHeadCnt == HeadId
select new
{
s.svhBalance,
refId = r == null ? 0 : r.refID // Adjust to the appropriate type of refID
};
var result = query.FirstOrDefault();
bool beenPaid = result != null && result.svhBalance == 0m;
With C# 6, you can change the bottom two lines to:
bool beenPaid = query.FirstOrDefault()?.svhBalance == 0m ?? false;
Having said that:
You're not currently using refId in the result anyway - why are you including it in the result?
Are you sure you want a left outer join at all?
Are you sure that taking the first result is really what you want? What if there are multiple results in the join?
Is there any reason you're not doing the whole thing in a query? Something like:
var paid = db.SrvHeads
.Where(s => s.svhAccID == accId && s.svhHeadCnt == HeadId)
.Any(s => db.Refererrants.Any(r => s.svhReferrer == r.refID
&& s.svhBalance == 0m);
.. but just for the precise semantics you want.
I had a similar issue.
Cause: You are using from "r" in r_join.DefaultIfEmpty(). You cannot use same alias name for left outer join.
Solution: Use different alias name if DefaultIfEmpty() cases. Eg: rEmpty
I modified the below query and its working.
var SrvRef = from s in db.SrvHeads
join r in db.Referrants on s.svhReferrer equals r.refID into r_join
from rEmpty in r_join.DefaultIfEmpty()
where s.svhAccID == accId &&
s.svhHeadCnt == HeadId
select new
{
s.svhBalance,
refID = rEmpty == null ? 0 : rEmpty.refID
};
what i think is causing an error is that svhBalance is an int32 value type and you are accessing a null value returned by SrvRef.FirstOrDefault().
please try the following line and let me know if it helped you.
if svhBalance is an int value type
var SrvRefObj= SrvRef.FirstOrDefault(); bool FBeenPaid = (((SrvRefObj!=null)&&(SrvRefObj.svhBalance
!=null))?(SrvRefObj.svhBalance == 0):(false))
else if it's a decimal value type
var SrvRefObj= SrvRef.FirstOrDefault(); bool FBeenPaid = (((SrvRefObj!=null)&&(SrvRefObj.svhBalance
!=null))?(SrvRefObj.svhBalance == 0M):(false))

how to add days to datetime by selecting in linq query

I'm trying to select nullable datetime by adding days.
As instance
COMPLETE_TIME = (x.VISIT_DATE.HasValue ? x.VISIT_DATE.Value.AddDays(1) : (DateTime?)null)
If datetime has value i want to add 1 days by selecting query as above.
If datetime does not have value i want to set nullable datetime by selecting query as above.
However if i try above code i get Error (please check bottom side for error)
All Query:
var result=
(from s in context.SURVEYs
join x in context.SURVEY_X on s.SURVEY_ID equals x.SURVEY_ID
join sas in context.SURVEY_ANSWER_SELECTION on s.SURVEY_ID equals sas.SURVEY_ID
join o in context.REP_OPTION on sas.OPTION_ID equals o.OPTION_ID
from PCO in context.REP_PARENT_CHILD_OPTIONS.Where(w => w.CHILD_OPTION_ID == sas.OPTION_ID).DefaultIfEmpty()
where
(s.SURVEY_ID == 5 || s.PARENT_SURVEY_ID == 5) &&
o.SUGGESTION != null &&
PCO.PARENT_OPTION_ID == null
select new
{
SUGGESTION = o.SUGGESTION,
DISPLAY_ORDER = "0",
SUGGESTION_TYPE = o.SUGGESTION_TYPE,
o.EXAMPLE_IMAGE_ID,
COMPLETE_TIME = (x.VISIT_DATE.HasValue ? x.VISIT_DATE.Value.AddDays(1) : (DateTime?)null) // Problem in this part
}).ToList();
Error:
An exception of type 'System.NotSupportedException' occurred in EntityFramework.SqlServer.dll but was not handled in user code
Additional information: LINQ to Entities does not recognize the method 'System.DateTime AddDays(Double)' method, and this method cannot be translated into a store expression.
Question:
How can i select added datetime or null datetime in select part ?
Any help will be appreciated.
Thanks.
If you are using EF 6 you could use on of the DbFunctions
var result=
(from s in context.SURVEYs
join x in context.SURVEY_X on s.SURVEY_ID equals x.SURVEY_ID
join sas in context.SURVEY_ANSWER_SELECTION on s.SURVEY_ID equals sas.SURVEY_ID
join o in context.REP_OPTION on sas.OPTION_ID equals o.OPTION_ID
from PCO in context.REP_PARENT_CHILD_OPTIONS.Where(w => w.CHILD_OPTION_ID == sas.OPTION_ID).DefaultIfEmpty()
where
(s.SURVEY_ID == 5 || s.PARENT_SURVEY_ID == 5) &&
o.SUGGESTION != null &&
PCO.PARENT_OPTION_ID == null
select new
{
SUGGESTION = o.SUGGESTION,
DISPLAY_ORDER = "0",
SUGGESTION_TYPE = o.SUGGESTION_TYPE,
o.EXAMPLE_IMAGE_ID,
COMPLETE_TIME = (x.VISIT_DATE.HasValue ? Dbfunctions.AddDays(x.VISIT_DATE.value, 1) : (DateTime?)null) // Problem in this part
}).ToList();

Convert string to int in linq-to-sql query: how to deal with values which cannot be converted?

I'm running this query against a database:
var result = (from leads in dc.T_DM_FactDemandeWebLeads
join demands in dc.T_DM_DimDemandeWebs on leads.DemandeWeb_FK equals demands.DemandeWeb_PK
join temps in dc.T_DM_Temps on demands.DateDemande_FK equals temps.Temps_PK
where leads.longitudeClient != null && (Convert.ToInt32(leads.GeolocDistanceRouteDistrib) > 1000*30) && (temps.Date > new DateTime(2000, 1, 1).Date)
select new Lead
{
lng = leads.longitudeClient,
lat = leads.latitudeClient,
distance = leads.GeolocDistanceRouteDistrib
}).Take(1000000);
Problem: This line is buggy:
(Convert.ToInt32(leads.GeolocDistanceRouteDistrib) > 1000*30)
as leads.GeolocDistanceRouteDistrib is a VARCHAR which takes "Unknown" in some cases, leading to a format exception:
Conversion failed when converting the varchar value 'Unknown' to data type int.
This problem is solved here, but the method cannot be converted to SQL.
Question: is there any way to rewrite the query so the conversion is done during the execution of the query?
Use the technique in this answer to create the IsNumeric sql function in your dbml file.
And use it in your query.
Something like this:
join temps in dc.T_DM_Temps on demands.DateDemande_FK equals temps.Temps_PK
where dc.ISNUMERIC(leads.GeolocDistanceRouteDistrib) // Added!
where leads.longitudeClient != null && (Convert.ToInt32(leads.GeolocDistanceRouteDistrib) > 1000*30) && (temps.Date > new DateTime(2000, 1, 1).Date)
select new Lead
Add .AsEnumerable() to your entity, then you can use all mothods
var result = (from leads in dc.T_DM_FactDemandeWebLeads.AsEnumerable()
join demands in dc.T_DM_DimDemandeWebs on leads.DemandeWeb_FK equals demands.DemandeWeb_PK
join temps in dc.T_DM_Temps on demands.DateDemande_FK equals temps.Temps_PK
where leads.longitudeClient != null && (Convert.ToInt32(leads.GeolocDistanceRouteDistrib) > 1000*30) && (temps.Date > new DateTime(2000, 1, 1).Date)
select new Lead
{
lng = leads.longitudeClient,
lat = leads.latitudeClient,
distance = leads.GeolocDistanceRouteDistrib
}).Take(1000000);

Categories