【发布时间】:2018-08-24 07:58:32
【问题描述】:
我想在将消息添加到数据库之前检查是否已经存在任何消息,但是我当前的查询将整个表加载到内存中。从我的代码生成的查询基本上只是select * from tableName。
如何重写此查询以在数据库中进行评估?
public void AddMessages(IEnumerable<Message> messages)
{
if (messages == null)
throw new ArgumentNullException(nameof(messages));
var duplicates = (from currMsg in context.Messages
where messages.Any(msg =>
msg.Prop1 == currMsg.Prop1 &&
msg.Prop2 == currMsg.Prop2 &&
msg.Prop3 == currMsg.Prop3)
select currMsg);
var messagesWithoutDuplicates = messages.Except(duplicates);
context.Messages.AddRange(messagesWithoutDuplicates);
context.SaveChanges();
}
我也可以在循环中运行它,但是我会创建许多数据库调用而不是 1,我更愿意在一次调用中执行此操作。
【问题讨论】:
-
见stackoverflow.com/questions/36514355/…,你需要类似的东西来产生基于
||的过滤器。 -
@IvanStoev 谢谢,现在我开始怀疑这是否值得努力。我怀疑这也不容易进行单元测试。
-
由于 IEnumerable
消息在客户端,我认为没有办法评估服务器上的 .Any() 。如果 context.Messages 是一个巨大的表,执行多个 db 调用并检查每个单独的消息会更快吗? -
嗯,基于
||的过滤器适用于任何 LINQ 方言,因此如果您使用 LINQ to Object 提供程序来模拟可查询对象,则不应该存在单元测试问题。但无论如何,总的来说,您当前的查询很好。当前的 EF Core 查询翻译器未能以某种方式将其翻译为服务器端评估。这是目前 EF Core 最大的 IMO 缺陷。 -
你不应该被 ORM 阻止做 SQL Server 中可能发生的事情。
MERGE在您的情况下看起来像 适合该工作的工具。
标签: c# entity-framework entity-framework-core