无法使用“”来形成正确的Linq查询;IN”;列表
本文关键字:Linq 查询 列表 IN | 更新日期: 2023-09-27 18:27:24
我有下面的SQL查询
;with cte as(
select a.*
from [dbo].[AccountViewModel] a
where a.COLLECTORID = 724852
and a.MONTH = 12
and a.YEAR=2015)
select *
from cte c
where c.DispCode in ('Deceased','DND','WN','WI','NC','NORESPONSE','SKIP','SHIFTED','SFU')
OR (c.DispCode in('PTP','DIB','WCE','DP') and convert(varchar(11), c.PTPDate) >=convert(varchar(11), getdate()))
OR (MONTH(c.LastPaymentDate) = 12 and YEAR(c.LastPaymentDate)=2015)
我需要将其转换为等效的Linq查询(C#)。
Cte部分与以下程序配合良好(我已经交叉检查了记录)
private List<AccountViewModel> GetAllAcountsForLoggedInAgents()
{
var allAcountsForLoggedInAgents = new List<AccountViewModel>();
allAcountsForLoggedInAgents = new ViewModelDatabase()
.Accounts
.Where(a =>
a.COLLECTORID == 724852 &&
a.MONTH == DateTime.Now.Month &&
a.YEAR == DateTime.Now.Year
)
.ToList();
return allAcountsForLoggedInAgents;
}
然而,CTE之外的零件工作不正常(意味着记录不正确)
GetAllAcountsForLoggedInAgents()
.Where
(
a =>
("Deceased,DND,WN,WI,NC,NORESPONSE,SKIP,SHIFTED,SFU".Split(',').Any(x => x.Contains(a.DispCode)))
|| ("PTP,DIB,WCE,DP".Split(',').Any(b => b.Contains(a.DispCode)) && a.PTPDate >= DateTime.Now)
|| (a.LastPaymentDate.Value.Month == 12 && a.LastPaymentDate.Value.Year == 2015)
)
我相信可能是我用错了"ANY"。
此条件与IN
子句不同
("Deceased,DND,WN,WI,NC,NORESPONSE,SKIP,SHIFTED,SFU".Split(',').Any(x => x.Contains(a.DispCode)))
因为它在其中一个字符串中搜索CCD_ 2。您应该使用相等:
("Deceased,DND,WN,WI,NC,NORESPONSE,SKIP,SHIFTED,SFU".Split(',').Any(x => x == a.DispCode))
这并不理想,因为Split
操作不是免费的,所以您不想将其作为查询的一部分。制作字符串的static
数组:
static readonly string[] DispCodeFilter = new string[] {
"Deceased", "DND", "WN", "WI", "NC", "NORESPONSE", "SKIP", "SHIFTED", "SFU"
};
...
(DispCodeFilter.Any(x => x == a.DispCode))
您的In条件不正确。它可以通过添加扩展方法来修复。我使用的是一个泛型方法,但如果您只需要/想要字符串,则可以使其特定于类型。我使用的是params,所以你可以一个接一个地提供项目,也可以通过拆分提供。
public static bool In<T>(this T item, params T[] items) {
return items.Any(i=> Equals(item, i));
}
GetAllAcountsForLoggedInAgents().Where( a => a.DispCode.In
("Deceased","DND","WN","WI","NC","NORESPONSE","SKIP","SHIFTED","SFU")
|| (a.DispCode.In("PTP,DIB,WCE,DP".Split(',')) &&
a.PTPDate >= DateTime.Now)
|| (a.LastPaymentDate.Value.Month == 12 && a.LastPaymentDate.Value.Year == 2015)
)
这与sql版本之间的一个区别,也是你可能不希望它是通用的原因,是它区分大小写:"wi"不等于"wi"。
以下是将SQL转换为Linq的两条简单规则
SQL Linq
============ ==========
IN (...) Contains
EXISTS (...) Any
其中Contains
是对应的Enumerable/Queryable
方法(不与string.Contains
混合)。
根据这个,你的Linq标准应该是这样的
var DispCodes1 = new [] { "Deceased", "DND", "WN", "WI", "NC", "NORESPONSE", "SKIP", "SHIFTED", "SFU" };
var DispCodes2 = new [] { "PTP", "DIB", "WCE", "DP" };
GetAllAcountsForLoggedInAgents()
.Where
(
a =>
DispCodes1.Contains(a.DispCode)
|| (DispCodes2.Contains(a.DispCode)) && a.PTPDate >= DateTime.Now)
|| (a.LastPaymentDate.Value.Month == 12 && a.LastPaymentDate.Value.Year == 2015)
)
dasblinkenlight的答案包含一个很好的观点,所以您可以使DispCodes1
和DispCodes2
是静态的,但这不是必需的。
另一件需要提及的事情是,您执行"CTE部分"的方式并不等同于SQL查询,其中cte
只是一个命名的子查询,整个查询在数据库中执行,而在您的实现中,cte
部分在数据库中运行,然后在内存中具体化,并使用Linq-to对象在内存中执行附加查询。为了使其完全等效,并让整个查询在数据库中执行,请将GetAllAcountsForLoggedInAgents
结果类型更改为IQueryable<AccountViewModel>
并删除ToList
调用。