I have the following code:
return this.ObjectContext.BranchCostDetails.Where(
b => b.TarrifId == tariffId && b.Diameter == diameter
||
In this case it is important to distinguish between IQueryable and IEnumerable. In short IQueryable is processed by a LINQ provider to deliver an optimized query. During this transformation not all C# statements are supported, as it either is not possible to translate them to a back-end specific query (e.g. SQL) or because the implementer did not foresee the need for the statement.
In contrast IEnumerable is executed against the concrete objects and, therefore, will not be transformed. So, it is quite common that constructs, which are useable with IEnumerable, cannot be used with IQueryable and also that IQueryables backed by different LINQ providers do not support the same set of functions.
However, there are some workarounds (like Phil's answer), which modify the query. Also, as a more general approach it is possible to drop back to an IEnumerable before continuing with the specification of the query. This, however, might have a performance hit - especially when using it on restrictions (e.g. where clauses). In contrast, when dealing with transformations the performance hit is a lot smaller, sometimes even non existent - depending on your query.
So the above code could also be rewritten like this:
return this.ObjectContext.BranchCostDetails
.AsEnumerable()
.Where(
b => b.TarrifId == tariffId && b.Diameter == diameter
|| (b.TarrifId==tariffId && !string.IsNullOrWhiteSpace(b.Diameter))
||(!b.TarrifId.HasValue) && b.Diameter==diameter
);
NOTE: Ths code will have an higher performance impact than Phil's answer. However, it shows the principle.