最近我遇到了修复bug的代码,如下所示。 它很难理解,并使变化看起来也很危险。 是否有任何简单的方法可以解决这样的问题,即De Morgan的法律或以不同的方式重写。
SomeReturnType xyz()
{
return (from m in this.context.tblMessages
where m.SystemActionID.HasValue &&
(userID == null || m.RecipientID == null || m.RecipientID == userID) &&
m.TargetUserType == userType &&
(
(territoryID.HasValue && !m.TerritoryID.HasValue) ||
(!territoryID.HasValue && !m.TerritoryID.HasValue) ||
(territoryID.HasValue && m.TerritoryID.HasValue && territoryID.Value == m.TerritoryID.Value)
) &&
(
(regionID.HasValue && !m.RegionID.HasValue) ||
(!regionID.HasValue && !m.RegionID.HasValue) ||
(regionID.HasValue && m.RegionID.HasValue && regionID.Value == m.RegionID.Value)
) &&
(
(teamID.HasValue && !m.TeamID.HasValue) ||
(!teamID.HasValue && !m.TeamID.HasValue) ||
(teamID.HasValue && m.TeamID.HasValue && teamID.Value == m.TeamID.Value)
) &&
m.SystemActionData == additionalData &&
(!completed.HasValue || m.IsSystemActionCompleted == completed.Value)
select m).FirstOrDefault();
} //function xyz ends
答案 0 :(得分:3)
首先,这段代码看起来像是试图将错误的SQL代码移到LINQ:这些语句包含参数检查,试图创建一个可以具有" optional"参数。看起来作者试图将存储过程移动到代码中。
这两件事都是糟糕的想法。
例如,您可以更改此内容:
(from m in this.context.tblMessages
where m.SystemActionID.HasValue &&
(userID == null || m.RecipientID == null || m.RecipientID == userID) &&
m.TargetUserType == userType &&
(
(territoryID.HasValue && !m.TerritoryID.HasValue) ||
(!territoryID.HasValue && !m.TerritoryID.HasValue) ||
(territoryID.HasValue && m.TerritoryID.HasValue && territoryID.Value == m.TerritoryID.Value)
) &&
到这个
if (userId==null)
return null;
var query=from m in this.context.tblMessages
where m.SystemActionID != null
&& (m.RecipientID == null || m.RecipientID == userID)
&& m.TargetUserType == userType ;
if (territoryID.HasValue)
query=query.Where(m=>m.TerritoryId==null || m.TerritoryId==teritoryID);
您可以用同样的方式简化语句的其余部分,例如:
if (regionID.HasValue)
query=query.Where(m=>m.RegionId==null || m.RegionId==regionID);
if (teamID.HasValue)
query=query.Where(m=>m.TeamID==null || m.TeamID==teamID);
LINQ查询永远不应该将参数与常量进行比较 - 为什么强制服务器执行常规检查,您可以轻松地在客户端上执行此操作?
这将导致查询更加简单,服务器更容易优化
答案 1 :(得分:1)
我在这种情况下使用IQueryable。我使用了一些虚拟名称而不是你的例子来展示自己的想法 - 你需要应用"其中"条款一步一步。
IQueryable<Account> query1 = from account in storage.Accounts
where account.Username == username
select account;
IQueryable<SomeNewTypeIfNecessary> query2 = from account in query1
where account.ID > 100
select new SomeNewTypeIfNecessary { ID = account.ID };
// Final call doing real query to database.
List<SomeNewTypeIfNecessary> accounts = query2.ToList();
此外,此类技术允许动态添加所需的语句(主要是where和orderby子句),以根据某些用户选择(例如排序方向)获取特定数据。