在Web应用程序中,我是开发人员团队的一员,我们将Entity Framework用作ORM。当我们执行SQL查询时,我们通常链接实体框架提供的IQueryable方法,从方法Items()
开始,这是DbSets的项目特定模型投影。我一直在尝试编写一个正则表达式模式,该模式可以找到不使用Select
方法的查询。
这是我们的代码通常的样子
Cars.Items()
.Where(x => x.Year == "1988")
.Select(x => new { x.Registration })
.ToList();
Cars.Items()
.Where(x => x.Id == 1923984)
.Select(x => new { x.Registration })
.FirstOrDefault;
这是我想要查询的那种查询
Cars.Items()
.Where(x => x.Id == 1923984)
.FirstOrDefault;
我尝试使用否定前瞻来排除具有Select()
方法的查询,但它们已包含在内,而且我很难想到另一种方法。
\.Items\(.*\)(\s*\..*\(.*\))*(?!\.Select\(.+\))(\s*\..*\(.*\))\;
我打破逻辑
\.Items\(.*\)
所有查询均以此方法开头(\s*\..*\(.*\))*
任意数量的链式IQueryable方法(?!\.Select\(.+\))
应排除Select()
方法(\s*\..*\(.*\))\
这可以是First()
,FirstOrDefault()
,Single()
或类似的;
结束查询答案 0 :(得分:3)
由于您已经捕获了此部分的所有内容,因此前方的负面展望是不起作用的原因:
\.Items\(.*\)(\s*\..*\(.*\))*
你需要首先向前看负面,然后包括一切。试试这个正则表达式:
\.Items\(.*?\)(\W.*(?!\.Select\(.+\)))?(\W.*)?\;
答案 1 :(得分:3)
我也试过为此创建一个正则表达式。您可以在此处进行测试:https://regex101.com/r/qRU2sP/5
正则表达式:Cars(?>\.(?!select)\w+(?:\([^)]*\))?\s*)+\;
与答案的答案之间的微小区别在于,这一点反映了整个陈述。
编辑:那么它是如何运作的?
我尝试捕捉重复部分(.Items()
或.Select()
),以便更容易维护/遵循模式。
Cars
我已经把Cars
放在了开头,因为正如这种方式,正则表达式引擎知道下一组字符是否有趣。这减少了所需的步骤量。也可以由\w+
替换,但随后会有更多步骤,因为整个文本中的更多字符与之匹配。
(?>
我在这里开始一个原子团。这意味着正则表达式引擎在遵循正则表达式模式时不会回溯。这大大提高了性能,因为如果模式的一部分失败,它将不会尝试其他可能性。 More detail here.
\.
字面上匹配.
字符。
(?!select)
否定前瞻 - 仅在select
时匹配。我在regex101.com上使用了不区分大小写的修饰符,但C#也支持这一点。否则只需将其更改为[Ss]elect
。
\w+
匹配任何单词字符a-zA-Z0-9_
至少一次。这与文字的where
或select
部分相符。
(?:
我在这里开始一个新的非捕获组。我这样做是因为模式的下一部分是可选的(方法/ lambdas的()
部分)。
\(
这只是字面匹配(
字符。
[^)]*
这匹配所有内容(包括无。请参阅*
)UNTIL遇到)
字符。
\)
字面匹配)
字符。
)?
我关闭了可选项(请参阅?
)组。请记住,这是每个方法/ lambda的()
的一部分,但它也可能是一个属性,因此()
部分必须是可选的。
\s*
匹配任何空白字符(如空格,制表符和换行符)尽可能多次。
)+
在这里,我们结束与文本的.Where(x => x)
部分匹配的组(至少一次。请参阅+
)。
\;
字面匹配;
字符。
就是这样!因此,性能上最大的欺骗是Cars
部分和(?>
原子组。