How to convert a string into a datetime in Linq to Entities query? - oracle

My Linq to entities query is written as below.
The datatype of DATECOLUMN1 in my ORACLE database is of string.
Datetime FilterStartDate = DateTime.Now;
var query = from c in db.TABLE1
join l in db.TABLE2 on c.FK equals l.PK
where (FilterStartDate >= DateTime.ParseExact(l.DATECOLUMN1, "dd/MM/yyyy", CultureInfo.InvariantCulture) : false) == true
select c;
Writing above query gives me an error of not supported. How can I convert DATECOLUMN1 into a datetime to compare it.
P.S. I do not have control over database schema, so changing datatype of column in Oracle database is not a feasible solution for me.

In you Model, add the following property to your partial class TABLE2:
public DateTime DATECOLUMN1_NEW
{
get
{
return DateTime.ParseExact(DATECOLUMN1, "dd/MM/yyyy", CultureInfo.InvariantCulture);
}
set { }
}
Then, in you LINQ query, use DATECOLUMN1_NEW (it's already in DateTime format) in place of DATECOLUMN1.

Erm.. I think the problem you are having is that you are putting ": false" in there.
It looks like you are trying to use a condtional operator (?:) but you forgot the "?".
I don't think you actually need this as you are just trying to determine if the date is greater or not. Also if ParseExact fails it will throw an exception (not what you want) so you should use TryParse instead and handle the true/false returned and the out value to determine whether or not the date is (a) Actually a date (b) less then FilterStartDate.
You can use two alternatives:
Use the function described in the answer here: How to I use TryParse in a linq query of xml data?
Use the following fluent syntax version which I think is more readable.
var query = db.Table1.Join(db.Table2, x => x.FK, y => y.PK, (x, y) => x).Where(x =>
{
DateTime Result;
DateTime.TryParse(x.Date, out Result);
return DateTime.TryParse(x.Date, out Result) && FilterStartDate >= Result;
});

Related

comparing "string" and "null" in linq to entity

My code:
string name;
db.Entities.Where(m=>m.name==(name??m.name))
throw:Should be CHAR, but get NCLOB.
//----------------
decimal? id;
db.Entities.Where(m=>m.id==(id??m.id))
The code is working.
my database is oracle.
What should I do to make the code working.?
Thanks.
Beware that in Oracle an empty string is NULL.
I don't know about Oracle + EF and type mappings. But this is not the way to make predicates optional anyway, because now the part x ?? x.y will always be part of the expression that is translated into SQL. This may hit query optimization and performance.
The way to do this is:
IQueryable<Entity> query = db.Entities;
if (!string.IsNullOrWhiteSpace(name))
{
query = query.Where(m => m.Name == name);
}

Convert string value to entity in linq where query

I am using jqgrid in MVC 4. I have written a method for getting a list in linq.
In my function I am getting all values of jqgrid with search criteria i.e. Operator AND/OR
, operations Equals to, not equals to etc. Here I am also getting the column name like Name, City, State etc.
My problem is I can't pass the column name directly in linq query i.e. I have to use the column name as x => x.Name
switch (rule.field)
{
case "Name":
query = query.Where(x => x.Name.StartsWith(rule.data, StringComparison.OrdinalIgnoreCase));
break;
case "Course":
query = query.Where(x => x.Course.StartsWith(rule.data, StringComparison.OrdinalIgnoreCase));
break;
}
In rule.field I am getting column Name i.e. Name, city, state etc. I want to pass the column name which I am getting in rule.filed in LINQ query instead of x =>x.Name.
Is there any way to do it so I can avoid writing switch cases?
You can use System.Linq.Dynamic, which can be installed as a Nuget package along with string.Format. The syntax would then look something like..
var newquery = query.AsQueryable()
.Where(
string.Format("{0}.ToUpper().StartsWith(#0)", rule.field)
,rule.data.ToUpper());
You could always use reflection:
query = query.ToList().Where(p => {
var field = p.GetType().GetProperty(rule.field);
var value = (String) field.GetValue(p);
return value.StartsWith(rule.data, StringComparison.OrdinalIgnoreCase);
});
Warning: Reflection is slow. Only use this for short lists. Since you're dealing with UI rendering, I'm assuming this won't be a problem.
edit: My example is assuming all properties are indeed properties (and not fields), and that all properties are Strings. You may need to alter the code for your specific case.

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"

Comparing date only on DateTime properties in EF4.

I find myself using the 'pattern' below rather unsettlingly often, when I want to select entities with based only on the date part of a DateTime property. EF doesn't parse the DateTime.Date property to T-SQL, so I end up using this code:
var nextDay = raceDate.Date.AddDays(1);
return EntityContext.RacingInfoes.SingleOrDefault(ri => ri.RaceDate >= raceDate && ri.RaceDate < nextDay);
It's the most readable solution I have found so far, but I don't like repeating it everywhere. However, I can't encapsulate it in any method as that method is not recognised by the Linq to Entities parser. Is there anything I can do about this?
You can encapsulate it by writing a method like this:
Expression<Func<T, bool>> OnDate<T>(Expression<Func<T, DateTime>> selector,
DateTime date)
{
var nextDay = date.Date.AddDays(1);
// Build up an expression tree, using Expression.AndAlso etc to
// compare the result of applying the selector with both date and nextDay
}
Then you'd write:
return EntityContext.RacingInfoes.SingleOrDefault(Helper.OnDate(x => x.RaceDate),
raceDate);
(OnDate is a bad name, but you see what I mean...)
I use this (often in combination with LINQKit's Invoke functionality) (which is similar to an implementation of Jon Skeet's answer):
public static class Criteria
{
...
public static Expression<Func<DateTime, DateTime, bool>> IsOnDate =
(dateTime, onDate) =>
dateTime >= onDate.Date `&&` dateTime < onDate.AddDays(1).Date;
...
}
This way, you can combine the criteria with other conditions in a single statement
EntityContext.RacingInfoes.AsExpandable().SingleOrDefault(ri =>
Criteria.IsOnDate.Invoke(ri.RaceDate, DateTime.Today) || someOtherCriteria);

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