time calculation within LINQ - linq

I want a linq query to return a calculated timespan,
i have used the timespan function before, but im not sure how to incorporate it into linq.
Basically the linq is returning a datetime field which i want to subtract from the current datetime to get days and hours.
Any help appreciated!
Thanks

Maybe something like:
from s in something
select DateTime.Now.Subtract(s.DateField)

Sure, the code below returns a date opened field, i want to calculate how many days the case is open and put it into a gridview.
var query2 = from cs in db.tblCases
where cs.date_closed.HasValue == false
select new
{
cs.date_case_opened),
};
gvReport.DataSource =
query2.Select(o => new {o.time });
gvReport.DataBind();
lbCount.Text = "Days open: " + ???

Related

Dynamic Linq on DataTable error: no Field or Property in DataRow, c#

I have some errors using Linq on DataTable and I couldn't figure it out how to solve it. I have to admit that i am pretty new to Linq and I searched the forum and Internet and couldn't figure it out. hope you can help.
I have a DataTable called campaign with three columns: ID (int), Product (string), Channel (string). The DataTable is already filled with data. I am trying to select a subset of the campaign records which satisfied the conditions selected by the end user. For example, the user want to list only if the Product is either 'EWH' or 'HEC'. The selection criteria is dynaically determined by the end user.
I have the following C# code:
private void btnClick()
{
IEnumerable<DataRow> query =
from zz in campaign.AsEnumerable()
orderby zz.Field<string>("ID")
select zz;
string whereClause = "zz.Field<string>(\"Product\") in ('EWH','HEC')";
query = query.Where(whereClause);
DataTable sublist = query.CopyToDataTable<DataRow>();
}
But it gives me an error on line: query = query.Where(whereClause), saying
No property or field 'zz' exists in type 'DataRow'".
If I changed to:
string whereClause = "Product in ('EWH','HEC')"; it will say:
No property or field 'Product' exists in type 'DataRow'
Can anyone help me on how to solve this problem? I feel it could be a pretty simple syntax change, but I just don't know at this time.
First, this line has an error
orderby zz.Field<string>("ID")
because as you said, your ID column is of type int.
Second, you need to learn LINQ query syntax. Forget about strings, the same way you used from, orderby, select in the query, you can also use where and many other operators. Also you'll need to learn the equivalent LINQ constructs for SQL-ish things, like for instance IN (...) is mapped to Enumerable.Contains etc.
With all that being said, here is your query
var productFilter = new[] { "EWH", "HEC" };
var query =
from zz in campaign.AsEnumerable()
where productFilter.Contains(zz.Field<string>("Product"))
orderby zz.Field<int>("ID")
select zz;
Update As per your comment, if you want to make this dynamic, then you need to switch to lambda syntax. Multiple and criteria can be composed by chaining multiple Where clauses like this
List<string> productFilter = ...; // coming from outside
List<string> channelFilter = ...; // coming from outside
var query = campaign.AsEnumerable();
// Apply filters if needed
if (productFilter != null && productFilter.Count > 0)
query = query.Where(zz => productFilter.Contains(zz.Field<string>("Product")));
if (channelFilter != null && channelFilter.Count > 0)
query = query.Where(zz => channelFilter.Contains(zz.Field<string>("Channel")));
// Once finished with filtering, do the ordering
query = query.OrderBy(zz => zz.Field<int>("ID"));

Printing Month Name in Linq

Is there any Inbuilt function in Linq to Print the month Name while working with LINQPAD?
I want to print the month name in the following Scenario
var query = from e in Employees
let month=e.BirthDate.GetValueOrDefault()
let birthmonth=month.ToString("MMMM")
select birthmonth;
query.Dump();
When I run this it is throwing NotSupportedException.
how to print the month name in Linq to Sql?
Rather than using ToString, try string.Format. Something like:
var query = (from e in Employees
let month = e.BirthDate.GetValueOrDefault()
let birthmonth = string.Format("{0:MMMM}", month)
select birthmonth);
query.Dump();
This seems to work from my local testing, although it is not included as part of the SQL query.
Do it in two steps, one to get the months from the database, then another using Linq-To-Objects to perform the formatting.
var birthDates = Employees.Select(e => e.BirthDate).ToList();
var query = birthDates.Select(d => d != null ? d.ToString("MMMM") : "Null");
query.Dump();
Whatever ORM you are using can't convert the string formatting part of you query into SQL that works on your database. So, doing it in two steps and using ToList to evaluate inbetween overcomes that problem.

How to compare only dates in linq?

In linq how can i diffentiate the date, like in sql we use
datediff(mm,getdate(),getdate())=0
now how can i write in linq, can any body help me thank you.
I think this is what you want:
var query = from entity in entities
where entity.SomeDateTime.Date == anotherDateTime.Date
select entity;
This only compares dates and not times.
You can use this code for comparing two dates using linq in C#
DateTime d1 = myDate1;
DateTime d2 = myDate2;
TimeSpan t1 = d2.Subtract(d1);
totalDays = t1.Days;
There's nothing special in Linq about date and time handling, so we should look at the plain .Net facilities.
A DateTime in C# is a date and time.
To get just the date component in C#, try this:
var now = DateTime.UtcNow; // or DateTime.Now for local time/day
DateTime today = now.Date;
This will give you the date and time at midnight of the same day.
If you want to get the difference in days between two DateTime objects:
public TimeSpan DiffDates(DateTime d1, DateTime d2)
{
return d1.Date - d2.Date;
}
// ...
if(DiffDates(dateTime1, dateTime2) == TimeSpan.Zero)
{
// ...
}
Alternately you could check directly if the dates are equal:
if(dateTime1.Date == dateTime2.Date)
{
// ...
}
If you skip the .Date property, then you will get incorrect results.

Why can't I cast nullable DateTime as string in a LinQ query?

I am trying to take a DateTime value, and if it is not null return the Short Time String. My query looks like this:
(TimeIn is NOT NULLABLE, whereas TimeOut is NULLABLE)
var times = from t in db.TimePostings
where t.MemberID == member.MemberID
select new
{
Date = t.TimeIn.ToShortDateString(),
TimeIn = t.TimeIn.ToShortTimeString(),
TimeOut = t.TimeOut.HasValue ? t.TimeOut.Value.ToShortTimeString() : "-------"
};
gvTimePostings.DataSource = times;
gvTimePostings.DataBind();
but this fails when I try to databind with the error:
Could not translate expression 'Table(TimePosting).Where(t =>
(t.MemberID == Invoke(value(System.Func1[System.String])))).Select(t
=> new <>f__AnonymousType84(Date = t.TimeIn.ToShortDateString(), TimeIn = t.TimeIn.ToShortTimeString(), TimeOut =
IIF(t.TimeOut.HasValue, (t.TimeOut ??
Invoke(value(System.Func`1[System.DateTime]))).ToShortTimeString(),
"-------"), Hours = ""))' into SQL and could not treat it as a local
expression.
I also get a similar error if I try to use:
TimeOut = t.TimeOut.HasValue ? Convert.ToDateTime(t.TimeOut).ToShortTimeString() : "-------"
however, if I change the TimeOut property to:
TimeOut = t.TimeOut.HasValue ? t.TimeOut.ToString() : "-------",
it works fine, but does not format the time like I want it (shortTimeString).
what's up with that?
As others have said, the problem is with trying to convert ToShortDateString etc to SQL. Fortunately, this is easy to fix: fetch the data with SQL, then format it in .NET:
var timesFromDb = from t in db.TimePostings
where t.MemberID == member.MemberID
select new { t.TimeIn, t.TimeOut };
var times = from t in timesFromDb.AsEnumerable()
select new
{
Date = t.TimeIn.ToShortDateString(),
TimeIn = t.TimeIn.ToShortTimeString(),
TimeOut = t.TimeOut.HasValue
? t.TimeOut.Value.ToShortTimeString()
: "-------"
};
The call to AsEnumerable() here basically means, "stop trying to process the query using SQL; do the rest in LINQ to Objects".
ToShortTimeString() has no translation in SQL. Because of that, converting the statement into a single SQL statement fails and the exception is thrown.
If you break the statement into two calls (one to retrieve the data and another to create the projection), things will work just fine:
// must call ToList to force execution of the query before projecting
var results = from t in db.TimePostings
where t.MemberID == member.MemberID
select new { t.TimeIn, t.TimeOut };
var times = from t in results.AsEnumerable()
select new
{
Date = t.TimeIn.ToShortDateString(),
TimeIn = t.TimeIn.ToShortTimeString(),
TimeOut = t.TimeOut.HasValue ?
t.TimeOut.Value.ToShortTimeString() :
"-------"
};
Have you tried:
TimeOut = t.TimeOut.HasValue ? t.TimeOut.ToString("d") : "-------",
This will normally give the short format of the DateTime. Whether it works or not will depend on whether it can be translated to SQL or not.
If it doesn't work you'll have to break the query into two parts. The first gets the data, the second format it. You'll have to convert the first query to a list (.ToList()) to force the SQL to be evaluated.
Simply, it's not supported by this specific linq provider.
Your linq query is converted into an expression tree. It is up to the SQL Linq provider to convert this expression tree into SQL. Understandably, it does not have the capability to translate every single .NET function.
Your solution is to explicitly run the SQL by calling ToArray or ToList, and then allow LinqToObjects to handle the rest.
var times = from t in db.TimePostings
where t.MemberID == member.MemberID
select new {
TimeIn = t.TimeIn,
TimeOut = t.TimeOut
};
var timesFormated = times.ToArray() // Runs the query - any further processing will be run in memory by the local .NET code
.Select(t => new {
Date = t.TimeIn.ToShortDateString(),
TimeIn = t.TimeIn.ToShortTimeString(),
TimeOut = t.TimeOut.HasValue ? t.TimeOut.Value.ToShortTimeString() : "-------",
Hours = ""
}
);
Your query is transformed by LINQ to an SQL that is fired against your database, and there is obviously no way to translate t.TimeOut.Value.ToShortTimeString() to SQL.
Possible solutions are:
First fetch your data from database (by calling .ToList() or .ToArray() on your LINQ query), that converts your IQueryable<> into IEnumerable<> and then apply your transformation for every row fetched.
Use a view that takes the original table and performs the conversion using CONVERT() function on the SQL Server and use it as the source for your Linq-to-SQL class. That would be performanter, but requires some server-side changes.
I had the same problem in a project in vb.net.
The solution I've found is based on the use of:
if(table.field.hasvalue, table.field.value.ToShortDateString, string.format("NULL"))
In this case, if the selected field (table.field) has a value this is converted into a date string otherwise if the field hasn't a value the output field is filled with string "NULL"

Linq to EF Expression Tree / Predicate int.Parse workaround

I have a linq Entity called Enquiry, which has a property: string DateSubmitted.
I'm writing an app where I need to return IQueryable for Enquiry that have a DateSubmitted within a particular date range.
Ideally I'd like to write something like
IQueryable<Enquiry> query = Context.EnquirySet.AsQueryable<Enquiry>();
int dateStart = int.Parse("20090729");
int dateEnd = int.Parse("20090930");
query = (from e in query
where(enq => int.Parse(enq.DateSubmitted) < dateEnd)
where(enq => int.Parse(enq.DateSubmitted) > dateStart)
select e);
Obviously Linq to EF doesn't recognise int.Parse, so I think I can achieve what I want with an Expression method that returns a predicate???
I've been playing around with PredicateBuilder and looking all over but I've successfully fried my brains trying to work this out. Sure I could add another property to my Entity and convert it there but I'd really like to understand this. Can anyone explain or give an example/link that doesn't fry my brains?
Thanks in advance
Mark
If you know your date strings are valid, and they're really in that order (which is a natural sort order) you might be able to get away with string comparisons:
IQueryable<Enquiry> query = Context.EnquirySet.AsQueryable<Enquiry>();
string dateStart ="20090729";
string dateEnd = "20090930";
query = (from e in query
where(enq => enq.DateSubmitted.CompareTo(dateEnd)) < 0)
where(enq => enq.DateSubmitted.CompareTo(dateStart)) > 0)
select e);

Resources