how to add days to datetime by selecting in linq query - c#

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();

Related

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))

Linq let and if

I am getting:
Non-static method requires a target.
The problem is that Status is null. I don't understand why, because there is a condition which clearly indicates if Status is null return 1.
var filterstatus = (from bq in basequery
let LastStatus = Status == null ? 1
: ((from sd in ems.SampleDatas
where sd.Reference_id == Status.id
&& sd.DateTimeUTC <= bq.DateTimeUTC
orderby sd.DateTimeUTC
select ((sd.Value >= StatusValue) ? 1 : 0)
).DefaultIfEmpty(1).FirstOrDefault())
select new { bq, LastStatus });
It's because it's converting the entire expression into SQL, and not doing the short-circuit in memory (the short circuit would be handled by the database).
You can write something like this, which will properly short-circuit in the database (but still generate the right hand side of the query).
var statusID = Status == null ? (int?)null : Status.id;
var filterstatus = (from bq in basequery
let LastStatus =
statusID == null ?
1 :
((from sd in ems.SampleDatas
where sd.Reference_id == statusID && sd.DateTimeUTC <= bq.DateTimeUTC
orderby sd.DateTimeUTC
select ((sd.Value >= StatusValue) ? 1 : 0)
).DefaultIfEmpty(1).FirstOrDefault())
select new { bq, LastStatus });
Ideally, though, you'd have two separate queries, depending on Status, as it's already known at that point whether the right hand side is required or not.

Can't compare dates using SQLite with EF6

I'm trying to compare dates using Linq to Entities on a SQLite database. The following code works, but I need to trim off the time portion to get the correct results.
return (from c in Context.Car
join d in Context.Driver on c.CarID equals d.DriverID
join r in Context.Rides on c.CarID equals r.RideID into rideJoin
from rides in rideJoin.DefaultIfEmpty()
where c.IsActive && d.IsActive
group rides by new { c.CarID, d.FullName, d.HireDate, d.FirstPayRiseDate } into grp
select new MyCustomClass
{
CarID = grp.Key.CarID,
Driver = grp.Key.FullName,
NumberOfRides = grp.Count(x => x != null && x.RideDate >= grp.Key.HireDate && x.RideDate <= grp.Key.FirstPayRiseDate)
}).OrderBy(x => x.Driver ).ToList();
I've tried using System.Data.Entity.DBFunctions like so and I get this error:
NumberOfRides = grp.Count(x => x != null && DbFunctions.TruncateTime(x.RideDate) >= grp.Key.HireDate && DbFunctions.TruncateTime(x.RideDate) <= grp.Key.FirstPayRiseDate)
SQL logic error or missing database no such function: TruncateTime
I also get the same error with DBFunctions.DiffDays()
I've also tried casting to Date like so and get this error:
NumberOfRides = grp.Count(x => x != null && x.RideDate.Date >= grp.Key.HireDate && x.RideDate.Date <= grp.Key.FirstPayRiseDate)
'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported
What gives? How am I supposed to do Date functions in Linq to Entities with SQLite??
I need to trim off the time portion to get the correct results
No you don't. If you want to include the rows from startDate through endDate inclusive then just use
... && x.RideDate >= startDate && x.RideDate < endDate.AddDays(1)
(Note that the second comparison is now "strictly less than".)
How are you storing dates on the database ? as unix time integrs ?
in that acse you can amend your connection string to include this following config setting and it will make it easy to read the datetime value via EF.
datetimeformat=UnixEpoch;datetimekind=Utc
So something like :
data source="|DataDirectory|\data.sqlite";datetimeformat=UnixEpoch;datetimekind=Utc
Ref: https://stackoverflow.com/a/24323591/3660930

Null Reference error in Linq query doesn't go away even checking for null

I have following query, "main" in query is a result from earlier steps.
var query = from a in main.AsEnumerable()
join b in result on a.id equals b.tId into joint
from c in joint.DefaultIfEmpty()
select new weekly()
{
id = a.id,
Mon = a.Mon
MHrs = (c.HoursList.Where(x => x.adt == "Monday")
.Select(y => y.thr).FirstOrDefault())
});
When I run this query I get System.NullReferenceException for MHrs. When I comment out the MHrs it runs fine.
I did try
y => y.thr == null ? null : 0
but it still didn't work.
Please let me know how to fix this query to run it without null reference exception. Thanks
When you use DefaultIfEmpty, joint.DefaultIfEmpty() will return null (default value of type) for non matching rows, so you will have to handle that:-
query= from a in main.AsEnumerable()
join b in result on a.id equals b.tId into joint
from c in joint.DefaultIfEmpty()
select new weekly()
{
id= a.id,
Mon= a.Mon
MHrs= c != null ? c.HoursList.Where(x=> x.adt=="Monday")
.Select(y=>y.thr).FirstOrDefault() : ""
});
Assuming thr is String.

List.contains throwing null exception?

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.

Categories