I am using dynamic Linq to return data for user-input search criteria. My query is working fine except for the user selected dates. My current code is:
StringBuilder whereClause = new StringBuilder();
if (startDate.HasValue || endDate.HasValue)
{
DateTime searchStartDate = startDate.HasValue ? startDate.Value : DateTime.MinValue;
DateTime searchEndDate = endDate.HasValue ? endDate.Value : DateTime.MaxValue;
whereClause.AppendFormat("Date >= {0} && Date <= {1}",
searchStartDate.Date.ToUniversalTime(),
searchEndDate.Date.ToUniversalTime());
}
if (whereClause.Length > 0)
{
return (from p in this.repository.GetQueryable<Party>() select p)
.Where(whereClause.ToString())
.ToList();
}
The query falls over because the comparison is being done between a DateTime field and a Int32 field, meaning the query has interpreted my date literals as integers.
How should I be formatting the dates?
Use
.Where("Date >= #0 && Date <= #1",
searchStartDate.Date.ToUniversalTime(),
searchEndDate.Date.ToUniversalTime())
instead.
In reply to Val's comment:
OK, then you can do:
whereClause.AppendFormat("Date.ToString() >= \"{0}\" && Date.ToString() <= \"{1}\"",
searchStartDate.Date.ToUniversalTime(),
searchEndDate.Date.ToUniversalTime());
You have to convert the Date in the query to a string and then compare it a quoted string literal. Without the quotes the parser is inerpreting the numbers inserted into the where clause as integers - what should explain the error you originally got.
Why are you parsing strings in a LINQ expression? The entire point of LINQ is to avoid that.
var q = from p in this.repository.GetQueryable<Party>() select p;
if (startDate.HasValue || endDate.HasValue)
{
var searchStartDate = startDate.HasValue ? startDate.Value : DateTime.MinValue;
var searchEndDate = endDate.HasValue ? endDate.Value : DateTime.MaxValue;
return
q.Where (p=> p.Date >= searchStartDate.ToUniversalTime()
&& p.Date <= searchEndDate.ToUniversalTime()).ToList();
}
return q.ToList();
UPDATE:
In response to comments: I'm building that one at run-time. The question isn't run-time vs compile-time; it's "in strings" vs "in code". StringBuilder lets you append text; LINQ lets to chain lamdbas. It all works out the same --- except your code is type-safe and syntax checked using lambdas.
To demostrate this concept further, the following code compiles & runs fine, and allows to you to change the Where clause based on the values of oddsOnly and lowerLimit.
int[] nums = {1,2,3,4,5,6,7,8,9,10};
bool oddsOnly = true;
bool lowerLimit = 5;
var q = from i in nums select i;
if (oddsOnly)
q = q.Where( n=> n%2 == 1);
if (lowerLimit != 0)
q = q.Where( n=> n >= lowerLimit);
foreach(var i in q)
Console.WriteLine(i);
Depending on how you set those values, it will use zero, one or both of the where clauses.
The Dynamic LINQ string would need to look something like:
"Date >= DateTime(2015, 10, 21)"
This is mentioned in the documentation in the DynamicQuery project in the download mentioned at http://weblogs.asp.net/scottgu/dynamic-linq-part-1-using-the-linq-dynamic-query-library.
Note, there isn't a new before the DateTime constructor.
I tried this and it works. I'm using Telerik's RadGrid control for ASP.NET AJAX. The grid builds the filter string and I needed to add the filter to my query to get the filter to execute in the database using LINQ to Entities. The problem is that the generated filter needed to be altered a little for it to work with LINQ to Entities as opposed to LINQ to Objects. It was doing a DateTime.Parse() which isn't supported in LINQ to Entities.
Related
I need to convert below query to linq in C#. Can someone share a free online tool or if you have good command in linq then please rewrite in C# supportive linq.
select
PaymentHolidayReason as Reason,
EmploymentStatus,
Cast(count(1) as Decimal) as Count,
Cast((select count(1)
from MortgageApplications MortgageApps
where PaymentHolidayReason is not null
and EmploymentStatus is not null) as Decimal) as Total
from
MortgageApplications MortgageApps
where
PaymentHolidayReason is not null
group by
PaymentHolidayReason,
EmploymentStatus
I would suggest you try to use the LinqPad and refer to the link below: http://www.linqpad.net
If not satisfied try: http://www.sqltolinq.com but I prefer LinqPad
i have write below query and it's working as same above sql statement.
var totalCount = _caseManagerContext.MortgageApplications.Where(x => x.PaymentHolidayReason != null && x.EmploymentStatus != null).Count();
var result = from mapp in _caseManagerContext.MortgageApplications
where mapp.EmploymentStatus!=null && mapp.PaymentHolidayReason!=null &&
mapp.LastModifiedDate >= initialDate && mapp.LastModifiedDate <= finalDate
group mapp by new { mapp.PaymentHolidayReason, mapp.EmploymentStatus } into g
select new { g.Key.PaymentHolidayReason, g.Key.EmploymentStatus, MyCount = g.Count(), Total=totalCount };
I am trying to get range data between two strings.
i have list of string which have data like this
Example:
K123456,
H123456,
J123456,
T122123,
So the first charter of string object contains an alphabet.
var StartLabwareid = int.Parse(obj.LWbStartId.Replace(labIni,""));
var EndtLabwareid = int.Parse(obj.LWbEndId.Replace(labIni, ""));
var LabWId = (from ai in _entities.Ai
join result in _entities.Re on ai.Id equals re.Id
where (Convert.ToInt32(ai.Id.Replace(Ini,"")) <= Startid ||
Convert.ToInt32(ai.Id.Replace(Ini, "")) >= Endtid)
select new MViewModel
{
ID = re.Id,
}).ToList();
Or I can use something else to compare to string and get data between that as we do in date range St rating and Ending Date
You cannot use C# functions such as Convert in Linq to Entities. Instead, you could do your comparison after the result is materialized, or use SqlFunctions. With SqlFunctions, you should get your result with combining Stuff and CharIndex functions. Modify the line below to suit your needs, since you are not providing all of the code.
SqlFunctions.Stuff(ai.Id, SqlFunctions.CharIndex(ai.Id, "replaceable"), 3, "")
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
I want my query to stop displaying time and just the date. This is what I've tried to far:
Query= (from z in ctx.Interactions
where z.ActivityDate <= StartDateTo
&& z.ActivityDate >= EndDateTo
&& z.Indepth == false
select new
{
Date = new DateTime(z.ActivityDate.Year, z.ActivityDate.Month, z.ActivityDate.Day),
Subject = z.Subject
}).ToList();
And
Query= (from z in ctx.Interactions
where z.ActivityDate <= StartDateTo
&& z.ActivityDate >= EndDateTo
&& z.Indepth == false
select new
{
Date = z.ActivityDate.Date,
Subject = z.Subject
}).ToList();
And both didn't work.
LINQ to Entities does not recognize the method 'System.String ToString(System.String)' method, and this method cannot be translated into a store expression. when trying to apply a string method.
You can use anyDate.ToString("ddMMyyyy");//any preferred format.
Not sure if that is what you are looking for!
Your queries return objects with Date & Subject properties.
In the Date property you are passing a DateTime object. In order to display the short date you have a "ToShortDateString()" function on a date.
If you dont want to work with a date and prefer selecting a string, then do the conversion inside the linq query.
Use this if you want to return strings:
var q = (from z in ctx.Interactions
where z.ActivityDate <= StartDateTo && z.ActivityDate >= EndDateTo && z.Indepth == false
select new { Date = z.ActivityDate.Date.ToShortDateString(), Subject = z.Subject }).ToList();
You would need to perform the formatting at the time of the binding. As you don't show the actual binding code, it is hard to specifically address your situation but lets look at what happens in your query:
Query= (from z in ctx.Interactions
where z.ActivityDate <= StartDateTo && z.ActivityDate >= EndDateTo && z.Indepth == false
select new { Date = z.ActivityDate.Date, Subject = z.Subject }).ToList();
Once LINQ handles this query, the resulting Query variable should be of type List<DateTime>. The way you have the query working you would return a list of DateTimes in a format like this:
2014-04-23 00:00:00
2014-03-28 00:00:00
etc...
In order to bind this without the time value, you need to call ToString() on each element (or the desired element) of the list at the time of binding.
Assuming you are using a ListBox or something similar you could write the following:
foreach (var date in myList) //this is the resultant list from the query
{
listBox1.Items.Add(date.ToString("MM/dd/yyyy");
}
If you are literally binding to a DataSource property, you will need to convert your List<DateTime> to a List<string> with the formatted values.
ToShortDateString() may help you.
Query= (from z in ctx.Interactions
where z.ActivityDate <= StartDateTo
&& z.ActivityDate >= EndDateTo
&& z.Indepth == false
select new
{
Date = z.ActivityDate.ToShortDateString(),
Subject = z.Subject
}).ToList();
convert date into string like below
string stringDate=string.empty;
stringDate=Convert.ToDateTime("2014-04-23 00:00:00").ToShortDateString();
it will give output like
2014-04-23
I have a table with a following format.
PID ID Label Value
------------------------------------------
1 1 First Name Jenna
1 2 DOB 10/12/1980
I need to retrieve all PIDs where First name starting with J and Month of DOB is 10.
in my code, I retrieve these in DataTable in C# and then tried to use LINQ to retrieve the results I want. This is just an example. These Labels could be anything user defines.
using LINQ I am able to retrieve all PIDs where First Name start with J, but every time I tried to Cast Value for DOB I get cast not valid error. I cannot change the column type in the database since Value could contain any type of information.
Here's a piece of my code. I am new to LINQ, and still trying to figure out around it.
var resultQuery = from r in query.AsEnumerable()
where (r.Field<string>("Label") == Label &&
r.Field<DateTime>("Value").Month == 10)
select r.Field<int>("PID");
Since not all items in the Value column of the table are convertible to DateTime, what you have will fail on invalid conversions. You can add in a clause that first checks that the value is a DateTime and only if it is, converts it and checks the .Month property.
DateTime d;
var resultQuery = from r in query.AsEnumerable()
where (r.Field<string>("Label") == Label &&
DateTime.TryParse(r.Field<string>("Value"), out d) &&
d.Month == 10)
select r.Field<int>("PID");
To potentially improve readability, you could also extract this out into a separate method:
var resultQuery = from r in query.AsEnumerable()
let d = TryGetDate(r.Field<string>("Value"))
where (r.Field<string>("Label") == Label &&
d != null &&
d.Month == 10)
select r.Field<int>("PID");
private DateTime? TryGetDate(string value)
{
DateTime d;
return DateTime.TryParse(value, out d) ? d : default(DateTime?);
}
You are going to end up filtering in memory which isn't very efficient.
So first select your data
var data= from r in query.AsEnumerable();
Then filter on the data
var filtered = from item in data
where item.Label == "Label"
&& Convert.ToDateTime(item.DOB).Month == 10
select item.PID;