在LINQ WHERE子句中有条件地允许null

时间:2013-11-24 13:51:02

标签: c# mysql linq lightspeed

工作:

我正在尝试在Contacts表和Permissions表之间执行LEFT OUTER JOIN。我有正确的工作基础,并返回一个联系人列表,无论他们是否有相应的权限。

// Query for Contacts
from contact in Contacts
join permission in Permissions on contact.Id equals permission.ObjectId into permissionGrp
from p in permissionGrp.DefaultIfEmpty()            
where p==null || (p!=null && /* ... condition based on the existence of a permission */)
select new { contact, permission = p };

生成WHERE SQL:

WHERE
(t1.PermissionId IS NULL OR 
    ((t1.PermissionId IS NOT NULL AND ... other conditions ... )))

问题:

我想调整以上内容来介绍'后备'检查;没有按预期工作。

要求:

  • 如果Permission没有Contact(即p==null),则只根据bool的预定allowed值包含该行。

尝试:

我以为我可以这样做where (p==null && allowed) || ...

// Fallback permission
bool allowed = false;

// Query for Contacts
from contact in Contacts
join permission in Permissions on contact.Id equals permission.ObjectId into permissionGrp
from p in permissionGrp.DefaultIfEmpty()

/* Added bool condition 'allowed' to control inclusion when 'p' is null */
where (p==null && allowed) || (p!=null && /* ... condition based on the existence of a permission */)
select new { contact, permission = p };

预期:

allowed = false(不接受null权限)

WHERE
    ((t1.PermissionId IS NOT NULL AND ... other conditions ... ))

allowed = true(接受null权限)

WHERE
(t1.PermissionId IS NULL OR 
    ((t1.PermissionId IS NOT NULL AND ... other conditions ... )))

实际结果:

即使在allowed=false

时,始终像true一样输出
WHERE
    ((t1.PermissionId IS NOT NULL AND ... other conditions ... ))

要点:

我希望我只是做一些容易修复的傻事 如何根据给定的null值过滤我的bool值记录?

2 个答案:

答案 0 :(得分:1)

您在此处执行GroupJoin。因此,第一部分permissionGrp的结果是匿名类型IGrouping<Permission>。这已经是OUTER JOIN的等价物。

您可以通过有条件地测试IGrouping<Permission>是否包含元素来实现您的目标:

from contact in Contacts
join permission in Permissions on contact.Id equals permission.ObjectId
    into permissionGrp
where allowed || g.Any()
from p in permissionGrp.DefaultIfEmpty()
select new { contact, permission = p };

请注意,from p in permissionGrp会再次展平分组,因此.DefaultIfEmpty()的情况仍然需要allowed == true

答案 1 :(得分:1)

我怀疑我正在使用的ORM(LightSpeed)中存在一个错误,我会引起他们的注意。

解决方法

我找到了一个合适的工作,使用let子句。

// Fallback permission
bool allowed = false;

// Query for Contacts
from contact in Contacts
join permission in Permissions on contact.Id equals permission.ObjectId into permissionGrp
from p in permissionGrp.DefaultIfEmpty()

/* Work around for 'allowed' not being honoured properly, using 'let' */
let isAllowed = allowed

/* Added bool condition 'isAllowed' to control inclusion when 'p' is null */
where (p==null && isAllowed) || (p!=null && /* ... condition based on the existence of a permission */)
select new { contact, permission = p };

结果

现在使用已知值与其自身的比较作为布尔检查。在这种情况下t0.ContactId

SQL allowed=true ... t0.ContactId = t0.ContactId

时的情况
WHERE
    ((t1.PermissionId IS NULL AND t0.ContactId = t0.ContactId) OR 
     (t1.PermissionId IS NOT NULL AND ... other conditions ...))

SQL allowed=false ... t0.ContactId <> t0.ContactId

时的情况
WHERE
    ((t1.PermissionId IS NULL AND t0.ContactId <> t0.ContactId) OR 
     (t1.PermissionId IS NOT NULL AND ... other conditions ...))