Entity Framework 4中简单的条件LINQ查询

10

我最近将这段代码迁移到了Entity Framework 4,但它失败了。显然,如果状态没有值,则返回所有匹配项;如果有值,则匹配那些user.StatusID == 1的值。

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

返回的异常:

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

然而,如果去掉条件测试,它就可以正常工作:

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

有什么想法吗?如何在EF 4中进行条件测试?肯定不是分开的if语句吧?

我一遍又一遍地在Linq to Sql中使用这些条件测试;很奇怪为什么在EF 4中这样做无效。可能出了什么简单的问题,也许在EF 4.0中有推荐的替代方法。

谢谢大家的帮助,
Graham


Edm.Int32是什么?它是你自己实现的System.Int32吗? - Stecya
1
@Stecya:http://msdn.microsoft.com/en-us/library/bb387164.aspx,似乎是EF的一些内部信息。 - Euphoric
7个回答

5

好的,我通过两种方法解决了它。

  1. 进行简单的空值测试。
  2. 在没有使用.Value方法的情况下测试本地转换的status变量。

两者都必须放置,否则它将继续以错误失败!测试值属性会很好,但我想查询必须非常简单 - 相当有趣!

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

如果没有更好的实现方式,我会等待一段时间再接受自己的答案。但是还是感谢大家的帮助。


EF越来越好了...感谢您的解决方案,今天它帮了我一个大忙。 - greenoldman

2

在where子句中进行null检查的另一种方法是分离可选参数,并仅在需要时应用它。

例如:

    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();

我认为它除了更易读一点之外,不会比您当前的解决方案提供更多的东西。

2

创建一个单独的变量来存储!status.HasValue,并在查询中使用它,这样怎么样?

我认为问题在于EF试图将您的状态变量作为参数传递到查询中,然后在SQL本身中执行逻辑。尝试检查生成的SQL。


哇,这个通过了,声明 var test = !status.HasValue 然后测试 test。但这并不好看。然而,这促使我尝试我能想到的每种转换和括号技巧,因为如果它像这样工作,那么它可以内联工作,它们都解决为false。嗯,还有别的想法吗? - GONeale
我认为问题在于 status 不是一个整数;并且在同一结构中比较一个枚举和一个整数类型时会产生混淆。也不能进行任何强制转换,因为它是可空的 :( - GONeale

1

看起来你已经找到了解决方案...

然而,只是提醒一下...我在VS 2010中对以下行没有任何问题

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

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

我没有收到任何错误信息,也返回了我期望的联系人对象...所以如果有什么问题,那就让我想知道你的user.StatusID字段的类型是什么?

祝你好运


0

status.HasValue 是什么?如果 statusUser 的一个字段,您应该这样调用它:user.status.HasValue

所以,简单地做这个:

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

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

嗨Farzin,它是可为null的int类型,而且是括号内方法的一个字段。 - GONeale
修改后,我知道这不是常见的解决方案,但对你有用!;) - Farzin Zaker

0

一开始我脑海中的印象是这样的:

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

但当我仔细看时,感觉它是错误的,那怎么办呢?

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

这背后到底是什么样的业务逻辑?

嗯,你的第二个查询总是会强制要求一个状态,但这并不一定是必须的。status 可以是 null,在这种情况下,我想获取所有条目。这就是为什么我使用 || 运算符的原因。 - GONeale

0

我认为你应该将 user.StatusID == 1 放在另一组括号中,因为我认为目前 EF 尝试将 || 操作应用于 status.HasValue 和 user.StatusId,然后将结果与 1 进行比较。


唉,没有运气。不过想法不错。 - GONeale

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接