3

I am using ef4 code first with a generic repository. My repository has a select method that looks like this:

public IEnumerable<T> Select(Func<T, bool> predicate)
{
    return objectSet.Where(predicate);
}

I am calling it with the following code

pushQueueRepository.Select(x => x.User.ID == user.ID && x.PageID == pageID);

*note - pushQueueRepository has been properly instantiated.

When I run this I am getting a NullReferenceException. When I look at it in debug after the exception is thrown it shows the error being x.User.ID == user.ID. When I mouse over x.User it is null. However when I expand x there us a User object in x.User (not null) that does have an id.

FYI x is a PushQueue object that is defined as such:

public class PushQueue : IEntity
{
    ...

    [Required]
    public User User { get; set; }

    ... 
}

This doesn't seem right, am I missing something?

Thanks.

3 Answers 3

2

The reason for getting the exception is because you are loading all of the PushQueues in memory and then trying to apply your predicate: x => x.User.ID == user.ID and because lazy loading is NOT enabled by your code, x.User will not be lazy loaded therefore the exception is being thrown. You've not mark User navigation property as virtual, so it didn't opt in to EF Lazy Loading. When expand it in debug mode in VS, you are explicitly loading it but at runtime it's not lazy loaded and that's why you see it's populated when you expand it.

To fix this you need to change the signature of your Select method as that's the main problem: you are passing Func<T, bool>, while it needs to be Expression<Func<T, bool>> instead. Basically you want your predicate to be executed in the data store and not in memory, so you need to change the code to this:

public IEnumerable<T> Select(Expression<Func<T, bool>> predicate)
{
    return objectSet.Where(predicate);
}

Of course alternatively you can keep the select method as it is now and enable lazy loading, this way, the NullReferenceException would go away but it will result in horrible performance at runtime since EF will be trying to lazy load User on every single PushQueue object and then apply your predicate:

public virtual User User { get; set; }     
Sign up to request clarification or add additional context in comments.

1 Comment

Good explanation! Please beware that you cannot enter any arbitrary function as the predicate. It needs to be directly calculable by the data store.
0

It's quite possible that by expanding x, you're causing other properties to be evaluated which then populate x.User.

Of course if this is an EF repository I'd expect the actual query to be executed in the database anyway, so what you see in the case of a query failure is somewhat unusual anyway. Have you tried looking at what query is executing in SQL?

2 Comments

When i check it in profiler it is essentially running SELECT * FROM [PushQueues]. Which is what I would expect. And the results are correct. Since User is not marked as virtual shouldn't it load immediately?
And if x.User is not populated initially then is there something that I need to do to get EF to allow me to query on a foreign key?
0

I think you need to use the .Include:

pushQueueRepository.Include("User").Select(x => x.User.ID == user.ID && x.PageID == pageID)

.Include forces EF to load the User object right away, which would otherwise be lazily loaded and thereby not available for your comparison on User.ID.

Having a string in the .Include is not very elegant and unfortunately not compile-time checked. You can do something like this:

pushQueueRepository.Include(typeof(User).Name)....

Not very elegant either, but at least it is checked by the compiler ;-)

1 Comment

Torben, Thanks for the help. While I believe this would have worked I used the suggestion by Morteza because it worked better in this situation. Cheers.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.