简体   繁体   中英

Comparing a nullable column throws “Unable to cast the type…” exception

My entity NewsItem has a nullable foreign key property: LibraryID of type int? .

My issue is when I query the property and compare it with any value except null , I get exceptions.

Initially my code was:

int? lid = ...
var results = context.NewsItems
    .Where(n => n.LibraryID == lid);

but it gives me no results at all, no matter what lid is.

So, I tried:

var results = context.NewsItems
    .Where(n => n.LibraryID.Equals(lid));

gives exception:

Unable to create a constant value of type 'System.Object'. Only primitive types or enumeration types are supported in this context.

and then I tried:

var results = context.NewsItems
    .Where(n => lid.Equals(n.LibraryID));

and got:

Unable to cast the type 'System.Nullable`1' to type 'System.Object'. LINQ to Entities only supports casting EDM primitive or enumeration types.

and this:

var results = context.NewsItems
    .Where(n => object.Equals(lid, n.LibraryID));

gives same exception as the last one.

Now I was desperate, so I tried to complicate stuff (like other forums suggested, for example here ):

var results = context.NewsItems
    .Where(n => (lid == null ? n.LibraryID == null : n.LibraryID == lid));

but still getting same exception.

So... any SIMPLE workarounds?

How about

var results = context.NewsItems
    .Where(n => lid.HasValue ? lid.Value == n.LibraryId.Value : (!n.LibraryId.HasValue) );

Hmm, that first snippet should work. I've used nullables like that many times. First thing I'd do is a sanity check just to make sure LibraryID is really int? and not long? or similar.

Other than that, you can try this:

var results = context.NewsItems
    .Where(n => (lid.HasValue ? n.LibraryID == lid.Value : !n.LibraryID.HasValue));

Or to avoid the ?: within the query:

var results = lid.HasValue 
    ? context.NewsItems.Where(n => n.LibraryID == lid.Value)
    : context.NewsItems.Where(n => !n.LibraryID.HasValue);

According to the MSDN docs (which I finally found), .Where() will only filter your collection. If you want to see if there are actually results, resolve by lazily executing the filtered query with .ToList(), GetEnumerator, or enumerating the collection with foreach;

This method is implemented by using deferred execution. The immediate return value is an object that stores all the information that is required to perform the action. The query represented by this method is not executed until the object is enumerated either by calling its GetEnumerator method directly or by using foreach in Visual C# or For Each in Visual Basic.

http://msdn.microsoft.com/en-us/library/bb534803.aspx

int? lid = ...
var results = context.NewsItems
    .Where(n => n.LibraryID == lid).ToList();
var results = context.NewsItems
    .Where(n => n.LibraryID.HasValue && n.LibraryID.Value == lid.Value );

edit:

Previous filter was based on my understanding that you wanted to filter to entires having a particular value. Updated will filter to null or value.

   var results = context.NewsItems
        .Where(n => !n.LibraryID.HasValue || n.LibraryID.Value == lid.Value );

It seems that EF does not find the correct operator overload. Therefore it produces wrong results if you set lid = null .

Use linq to objects by adding AsEnumerable() to your query and everything is fine:

var results = context.NewsItems.AsEnumeryble().Where(n => n.LibraryID == lid);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM