使用EF4,如何跟踪记录成为Skip().Take()结果集的次数?

4

使用EF4,我运行了一个以以下常用函数结尾的搜索查询:

query = query.Skip(5).Take(10);

数据库中的这些记录有一个名为ImpressionCount的列,我想用它来计算每个记录在搜索结果页面上显示的次数。

最有效的方法是什么?从我的角度来看,我只需要查看结果集,获取ID列表,然后再次使用ADO.NET访问数据库执行以下操作:

UPDATE TableName SET ImpressionCount = ImpressionCount + 1 WHERE Id IN (1,2,3,4,5,6,7,8,9,10)

似乎很简单,只是想知道是否有一种更.NET 4 / Linq的方法来做到这一点,我没有想到的方法。不涉及对数据库的另一个命中也很好。 :)
编辑:所以我倾向于IAbstract的响应作为答案,因为似乎没有“内置”的方法来做到这一点。我没想到有,但问一下也无妨。然而,我想提出的唯一其他问题是:是否可能编写一个SQL触发器,仅在此特定查询上运行?我不希望ImpressionCount更新每个记录的每个选择语句(例如,当某人去查看详细页面时,那不是印象 - 如果管理员在后端编辑记录,则不是印象)...可以使用LINQ实现吗?
SQL Server需要能够识别该查询是由该Linq命令生成的,不确定是否可能。这个网站预计会有相对繁重的流量,所以我只是尽可能地进行优化,但如果过度,我可能会再次针对每个结果页面访问一次数据库。

最终结果是一个“副作用”--“非棘手”的方法将是对每个结果进行循环并逐个更新,这不符合其他要求。 - user166390
2个回答

5

我认为,按照你现有的SQL命令进行操作是更好的选择。虽然我们有LINQ,但并不意味着它总是最好的选择。你的语句可以通过一次调用来更新印象计数,并且应该相当快速。


2
+1 我同意,使用原始的 SQL 并不意味着你违反了法律,但我们应该根据情况使用最好的工具。 - Akash Kava

1

你可以在返回结果中使用.Select修改每个元素, 但这不是C# / linq的惯用方式,所以最好使用foreach循环。

例如:

var query = query.ToList().Select(x => { x.ImpressionCount++; return x; });

正如IAbstract所说,要注意性能问题。使用上面的示例或foreach将执行10次更新。你的一个更新语句更好。

我知道Linq2NHibernate也有同样的问题 - 尝试坚持使用Linq对于更新并不好(这就是为什么它被称为“语言集成查询”);

编辑:

实际上,EF4或NHibernate可能无法解析选择表达式,意识到它是一个更新,并将其转换为更新语句并执行,但肯定没有一个框架会这样做。如果这是可能发生的事情,你需要一个新的.Update()扩展方法来明确说明你正在修改数据。使用.Select()是一种肮脏的hack。

这意味着你完全可以为 IQueryable<T> 编写自己的 .Update(x => x.ImpressionCount++) 扩展方法,以输出所需的 SQL 并调用 ExecuteStoreCommand,但这需要很多工作。


我会因为使用Select引入副作用而刺伤某人。此外,它也不能减少SQL语句/在for-each中的传输次数。 - user166390
@pst - 我同意,但我正在使用Jon Skeet的方法,“不要这样做,但如果您忽略我的警告,这是您将如何做到。” - Scott Whitlock

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