Question

I'm replacing an sad, atrocious VB6 desktop app with a beautiful shiny new web app, and trying to wash away as many sins of the past as I can.

The old app had this raw, dangerous SQL call that it would fire off using ADO:

strRequest = "Select * from tblTransactions where trans_date between " & strStartDate & " and " & strEndDate & " order by trans_date"

The date column, trans_date, is char(10). Changing the table is beyond my control.

The new app is using Entity Framework 6.

I know that there is no "between" keyword in EF, and if it were a datetime, I would simply do:

.Where(x => x.trans_date >= startDate && x.trans_date <= endDate)

But I obviously can't compare strings this way, where SQL happily will. Additionally, I can't do this:

var records = (from t in Db.tblTransactions
               where Convert.ToDateTime(t.trans_date) >= startDate
               && Convert.ToDateTime(t.trans_date) <= endDate
               select t)

because LINQ-To-Entities will not do ToDateTime. (LINQ to Entities does not recognize the method 'System.DateTime ToDateTime(System.String)' method, and this method cannot be translated into a store expression.)

Any idea on how this can be done in EF?

Was it helpful?

Solution

Although is also quite ugly, you can use DbContext.Database.SqlQuery to run the query directly in the database. The good news is that the result of running this query will be mapped to the entity type in your db context. I.e. you will not get an anonymous type collection, but a collection of the class that you have mapped to tblTransactions, provided you've defined that mapping.

There is no way to: use a CLR (C#) function that translates as a conversion from string to date, or to number, or a function or operator for comparing strings which is trasnlated to SQL or invoke a SQL UDF defined for this.

I've also pointed out in a comment that, if you're allowed to create views you can map to a view which has columns converted from string to datetime (or to number). Or use computed columns. You'd have to adapt your entity to support the extra columns.

This is a comprehensive list of functions that can be translated from CLR to SQL:

Surprisingly, none of them offers a direct solution to your problem.

OTHER TIPS

I would do this:

  1. Configure EF to do all the CUD using stored procedures
  2. Create a view that converts the char(10) to a date.
  3. Map the Transactions entity to the view
  4. Alter the generated stored procedures to do the CUD on the underlying table

Alternatively if the string is held in a sortable format such as YYYYMMDD (or can be changed to one) then you could use string comparison.

EDIT Following your comment that tells us that the string in the database is formatted in a way that means an alphabetical sort will sort dates chronologically (well it had to be or the original code wouldn't have worked would it?).

Then you need to convert your dates to strings in the same format in order to use string comparison:

string formattedStartDate = startDate.ToString("YYYY-MM-DD")
string formattedEndDate = endDate.ToString("YYYY-MM-DD")

and your where clause should work:

.Where(x => x.trans_date >= formattedStartDate 
            && x.trans_date <= formattedEndDate)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top