Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple conditional LINQ query in Entity Framework 4

I have recently migrated this code to Entity Framework 4 and it is failing. Obviously if status does not have a value, return all matches, if it does have a value match ones where user.StatusID == 1.

return users.SingleOrDefault(
                user =>
                user.Username == username &&
                user.EncryptedPassword == password &&
                (!status.HasValue || user.StatusID == 1)
                );

Exception returned:

ArgumentException: The specified value is not an instance of type 'Edm.Int32'
Parameter name: value

However, removing the conditional test and it works fine:

return users.SingleOrDefault(
                user =>
                user.Username == username &&
                user.EncryptedPassword == password &&
                user.StatusID == 1
                );

Any ideas? How do you perform conditional testing in EF 4? Surely not separate if lines?

I use these conditional tests time and time again in Linq to Sql; it is really odd as to why this is not functioning in EF 4. There must be something simple going wrong, perhaps there is a recommended alternate way of doing things in EF 4.0.

Thanks for your help guys,
Graham

like image 215
GONeale Avatar asked Apr 26 '11 10:04

GONeale


4 Answers

Ok, I solved it by a combination of two things.

  1. Doing a simple null test.
  2. Testing the local cast status variable without the .Value method.

Both must be in place otherwise it will continue to fail with the error! It would have been nice to test the value property, but I guess the query must be really simple - quite interesting!

return users.SingleOrDefault(
                user =>
                user.Username == username &&
                user.EncryptedPassword == password &&
                (status == null || user.StatusID == (int) status)
                );

I will wait for any better implementation otherwise accept my own answer. But thanks for everybody's help.

like image 92
GONeale Avatar answered Nov 17 '22 22:11

GONeale


How about creating separate variable for !status.HasValue and using this instead in query?

I think problem here is that EF tries to pass your status variable as parameter into the query and then do the logic in the SQL itself. Try checking what SQL is generated.

like image 44
Euphoric Avatar answered Nov 17 '22 20:11

Euphoric


An alternative way to doing the null check within the where clause would be to seperate out the optional parameter and only apply it if required.

e.g.

    var data = users.Where(
        user =>
            user.Username == username &&
            user.EncryptedPassword == password
        );

    if (status.HasValue)
    {
        data = data.Where(user => user.StatusID == status.Value);
    }

    return data.FirstOrDefault();

I don't think it'll offer much over your current solution other than a little more readability.

like image 37
Mike Avatar answered Nov 17 '22 22:11

Mike


Seems like you've already found a solution...

However, just fyi... i have no problem with the following line in VS 2010

  Nullable<int> status = 0;
  String username = "Alexandre 2";

    var test = _context.Contacts.SingleOrDefault(c => c.FirstName == username && (!status.HasValue || c.ContactID == 1));

I get no errors and the Contact object i expect is return ... so if anything, it makes me wonder what is the type of your user.StatusID field?

best of luck

like image 1
jonchicoine Avatar answered Nov 17 '22 20:11

jonchicoine