score:1

Accepted answer

You get the exception because you work with IQueryable. Entity Framework will try to translate the predicate in the where clause into SQL but EF doesn't know how to translate your method.

If you don't want to (or can't) change the database you still have a few options:

  1. Pull all rows to the client side and do the filtering on the client. You do this by changing from IQueryable to IEnumerable:

    return GetAllProducts()
      .AsEnumerable()
      .Where(m => Equals(DateUtilities.ExtractYear(m.ProductCreationDate), year))
      .AsQueryable();
    
  2. To be more efficient you can use your own SQL (this requires EF 4.1 and only avoid pulling all products to the client, not the scan on the server):

    return context
      .Products
      .SqlQuery("select * from Products where substring(ProductCreationDate, 1, 4) = '2012'")
      .AsQueryable();
    

    Note that I was lazy and hardcoded the SQL. You should probably parametrize it and make sure you avoid any SQL injection attacks.

score:1

You could do the extraction inline, something like this:

public IQueryable<Products> GetCreatedProducts(int year)
{
        string sYear = year.ToString();
        return GetAllProducts().Where(m => m.ProductCreationDate.Substring(0,4) == sYear);
}

score:2

I don't think this is really a bug so much as a limitation -- there's no SQL version of ExtractYear, so it's not possible to execute this query.

You'll have to rewrite the query to either use only SQL-compatible commands (like some other answers have shown) or pull lots of data out of the database and do the filtering with LINQ-to-Objects (this could potentially be very expensive, depending on what you're querying and how many of the records match).

score:4

My first question would be why are you storing a date in the database as a string? Store it as a date and use data comparison against it through Linq.

The issue that you're coming up against is Linq doesn't understand what the method ExtractYear is when it tries to compile your Linq statement to raw SQL

EDIT Another alternative would be to create a view in the database and query against the view with a computed column that represents the string value as a datetime.

score:4

In this case you could go the other way:

GetAllProducts().Where(m => m.ProductCreationDate.StartsWith(year.ToString()));

Rather than extract the year from the string, find all strings beginning with the year you're after.

I'm not sure if these will work for the Month and Day searches:

var monthString = String.Format("{0:00}", month);
GetAllProducts().Where(m => m.ProductCreationDate.Substring(4,2) == monthString);  

var dayString = String.Format("{0:00}", day);
GetAllProducts().Where(m => m.ProductCreationDate.Substring(6,2) == dayString);

Related Query

More Query from same tag