"where" clause: entity id is in a potentially null array

.net c# entity-framework linq-to-entities

Question

I have an array of office ids, and the array is potentially null. I want the EF query to return all records if the officeIdsToSelect array is null, or only the matching records if it is not null. However this:

int[] officeIdsToSelect = new int[] { 1, 2, 3 };
Office[] selectedOffices = (from item in new TdsDb().Offices
                            where (officeIdsToSelect == null || officeIdsToSelect.Contains(item.OfficeID))
                            select item).ToArray();

throws an exception:

System.NotSupportedException : Cannot compare elements of type 'System.Int32[]'. Only primitive types (such as Int32, String, and Guid) and entity types are supported.

Specifically Linq to Entities is objecting to officeIdsToSelect == null. I understand what it's saying (one of the clearer EF error messages...)

So how can I get what I want here?

1
3
3/10/2016 11:59:29 PM

Accepted Answer

EF can't translate officeIdsToSelect == null to SQL.

In the other hand, EF is clever enough to translate officeIdsToSelect.Contains(item.OfficeID) to WHERE OfficeID IN (1, 2, 3).

So basically, you could simply do:

Office[] selectedOffices;
if (officeIdsToSelect == null)
{
    selectedOffices = new TdsDb().Offices.ToArray();
}
else
{
    selectedOffices = (from item in new TdsDb().Offices
                            where officeIdsToSelect.Contains(item.OfficeID)
                            select item).ToArray();
}

EDIT:

If your actual query is more complicated and you don't want to duplicate it, what you could do is conditionally add a Where clause depending on the value of your int array.

// Here's a query that is NOT YET executed (deferred execution)
var query = (from item in new TdsDb().Offices
                            ...... your whole complicated request here
                            select item);

// Conditionnally adds a where clause if required
if (officeIdsToSelect != null)
{
    // Still not yet executing the query. We're just building the query for now
    query = query.Where(z => officeIdsToSelect.Contains(z.OfficeID));
}

// OK, now executes the query and get the results
Office[] selectedOffices = query.ToArray();

if the conditional Where doesn't overwrite the original Where clause; but is addative

Yes, that's the power of LINQ to Entities: fluent programming and deferred execution.

Fluent programming means you can chain methods, and this is possible with LINQ thanks to the IQueryable extension methods.

For example, IQueryable<T>.Where(...) returns also an IQueryable<T> object. It internally adds a predicate to the query, then returns the query you specified as parameter.

The other important part is the deferred execution. This allow to not execute the query until the data is actually requested. It's only when you actually need the data that the request in actually executed against your database. In the above example, it's the .ToArray() command that actually executes the query.

See this nice MSDN article for details about query execution mechanisms.

6
5/17/2013 12:29:50 PM

Popular Answer

try this;

int[] officeIdsToSelect = new int[] { 1, 2, 3 };
var selectedOfficeCount = officeIdsToSelect.Count;
Office[] selectedOffices = (from item in new TdsDb().Offices
                                where (selectedOfficeCount == 0 || officeIdsToSelect.Contains(item.OfficeID))
                                select item).ToArray();


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow