我想在将任何消息添加到数据库之前检查是否已经存在任何消息,但是我当前的查询将整个表加载到内存中。从我的代码生成的查询基本上只是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();
}
我也可以循环运行它,但随后我将创建许多db调用,而不是1个,而我希望在单个调用中执行此操作。
答案 0 :(得分:0)
如果要检查表中有多少行,可以使用SELECT COUNT(*)FROM TABLE。 在执行任务之前执行此查询。
,或者如果您希望更新是否无法插入行(重复) 您需要为此使用merge-insert。
合并插入(MySql)=> https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html
合并插入(Oracle)=> https://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_9016.htm#SQLRF01606
答案 1 :(得分:0)
根据您的用例,您可能需要一个一个地插入它们,并信任数据库的唯一索引(您有一个,对不对?),如果它是重复的,则将它丢回您的脸。 / p>
代码除之外,还有两个弱点:并发性(如果在检查重复项时有人插入的话)以及要插入的记录本身可能是重复项,而不是重复项检查。
答案 2 :(得分:0)
由于没有一个简单的方法可以完成此操作,因此我决定牺牲性能并保留可读性和可测试性。这是我的解决方案:
using (var transaction = context.Database.BeginTransaction())
{
try
{
foreach (var message in messages)
{
var exists = context.Messages.Any(msg => msg.Prop1 == message.Prop1 &&
msg.Prop2 == message.Prop2 &&
msg.Prop3 == message.Prop3 &&);
if (!exists)
{
context.Messages.Add(message);
}
}
context.SaveChanges();
transaction.Commit();
}
catch (Exception ex)
{
_logger.Error(ex);
transaction.Rollback();
throw;
}
}