There are two solutions to this problem.
I'll first explain why it is throwing an error. EF is converting your code to an SQL Expression
. When working with Expression
you cannot parse in any C# code and expect it to work. EF needs to be able to translate it to SQL. That is why you are getting the exception saying that it can't translate your code.
When working directly in the Where
clause on the DbSet
or the DbContext
you are actualy talking to the Where
method for an IQueryable
. Which has a parameter of Expression<Func<bool, T>>
where T
is your DbSet<T>
type.
You either need to simplify your query so it can be translated to SQL. Or you can convert your IQueryable
to an IEnumerable
.
When you want to run your query on the SQL server, you need to use the first approach. But when you can run your query on the client you can use the second approach.
The first approached as mentioned by vivek nuna is using EntityFunctions
. It might not be enough for your use case, because it has limited functionality.
The statement made that DateTime.Now
is different on each iteratoion is not true. Because the query is converted once, it isn't running the query on every iteration. It simply doesn't know how to translate your query to SQL.
https://learn.microsoft.com/en-us/dotnet/api/system.data.objects.entityfunctions?view=netframework-4.8
The second approach means adding AsEnumerable
after your DbSet
. This will query all your data from your SQL server, and evaluate in C#. This is usually not recommended if you have a large data set. Example:
var chemicals = _context.Chemical.AsEnumerable(); // this will get the complete collection
chemicals.Where(i => i.Value == true); // everything will work now
And answer to a "better" approach. It's a bit cleaner code:
If you have navigation properties for your Base
and Catalyst
you can also include this in your query.
Note that you can still query server side before pulling everything client side using a Where
on the _context.Chemical
and then including and calling AsEnumerable
.
var chemicals = _context.Chemical.Include(i => i.Base).Include(i => i.Catalyst).AsEnumerable();
foreach (var chemical in chemicals.Where(i => true)) // set correct where clause
{
_warningService.SendSafetyWarning(chemical, chemical.Base, chemical.Catalyst);
}