Entity Framework Core: Update, Attach ou ExecuteUpdate
Quando pensamos em Update utilizando o Entity Framework temos algumas abordagens que podemos seguir, vamos explorar as principais: Update (SaveChanges), Attach ou ExecuteUpdate.
A mais comum é utilizar o método SaveChanges após realizar as alterações no contexto, o Attach e a partir do EF Core 7.0, temos o ExecuteUpdate.
Para exemplificar, vamos considerar uma entidade tabela_a, que foi preenchida com 100 registros, a entidade apresenta as seguintes propriedades:
[Table("tabela_a")]
public partial class TabelaA
{
[Key]
[Column("id")]
public Guid Id { get; set; }
[Required]
[Column("texto")]
[StringLength(100)]
public string Texto { get; set; }
[Column("booleano")]
public bool Booleano { get; set; }
[Column("data", TypeName = "timestamp without time zone")]
public DateTime? Data { get; set; }
[Column("criacao", TypeName = "timestamp without time zone")]
public DateTime Criacao { get; set; }
}
Update com SaveChanges
Na abordagem tradicional temos que carregar os dados para o contexto, realizar as alterações e depois chamar o método SaveChanges.
Stopwatch sw = new Stopwatch();
sw.Start();
var registros = context.TabelaAs.AsTracking(QueryTrackingBehavior.TrackAll)
.Where(x => x.Criacao >= DateTime.Now.AddDays(-30)).ToList();
foreach (var item in registros)
{
item.Data = DateTime.Now;
}
int registrosAfetados = context.SaveChanges();
sw.Stop();
Console.WriteLine($"Registros afetados: {registrosAfetados} - Tempo: {sw.lapsedMilliseconds} ms");
Vamos executar o código acima e analisar como ele se comporta, o log gerado foi o seguinte:
info: 11/09/2025 18:41:36.546 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
Executed DbCommand (151ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT t.id, t.booleano, t.criacao, t.data, t.texto
FROM tabela_a AS t
WHERE t.criacao >= now()::timestamp + INTERVAL '-30 days'
info: 11/09/2025 18:41:36.795 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
Executed DbCommand (70ms) [Parameters=[@p1='?' (DbType = Guid), @p0='?' (DbType = DateTime2), @p3='?' (DbType = Guid), @p2='?' (DbType = DateTime2), @p5='?' (DbType = Guid), @p4='?' (DbType = DateTime2), @p7='?' (DbType = Guid), @p6='?' (DbType = DateTime2), @p9='?' (DbType = Guid), @p8='?' (DbType = DateTime2), @p11='?' (DbType = Guid), @p10='?' (DbType = DateTime2), @p13='?' (DbType = Guid), @p12='?' (DbType = DateTime2), @p15='?' (DbType = Guid), @p14='?' (DbType = DateTime2), @p17='?' (DbType = Guid), @p16='?' (DbType = DateTime2), @p19='?' (DbType = Guid), @p18='?' (DbType = DateTime2), @p21='?' (DbType = Guid), @p20='?' (DbType = DateTime2), @p23='?' (DbType = Guid), @p22='?' (DbType = DateTime2), @p25='?' (DbType = Guid), @p24='?' (DbType = DateTime2), @p27='?' (DbType = Guid), @p26='?' (DbType = DateTime2), @p29='?' (DbType = Guid), @p28='?' (DbType = DateTime2), @p31='?' (DbType = Guid), @p30='?' (DbType = DateTime2), @p33='?' (DbType = Guid), @p32='?' (DbType = DateTime2), @p35='?' (DbType = Guid), @p34='?' (DbType = DateTime2), @p37='?' (DbType = Guid), @p36='?' (DbType = DateTime2), @p39='?' (DbType = Guid), @p38='?' (DbType = DateTime2), @p41='?' (DbType = Guid), @p40='?' (DbType = DateTime2), @p43='?' (DbType = Guid), @p42='?' (DbType = DateTime2), @p45='?' (DbType = Guid), @p44='?' (DbType = DateTime2), @p47='?' (DbType = Guid), @p46='?' (DbType = DateTime2), @p49='?' (DbType = Guid), @p48='?' (DbType = DateTime2), @p51='?' (DbType = Guid), @p50='?' (DbType = DateTime2), @p53='?' (DbType = Guid), @p52='?' (DbType = DateTime2), @p55='?' (DbType = Guid), @p54='?' (DbType = DateTime2), @p57='?' (DbType = Guid), @p56='?' (DbType = DateTime2), @p59='?' (DbType = Guid), @p58='?' (DbType = DateTime2), @p61='?' (DbType = Guid), @p60='?' (DbType = DateTime2), @p63='?' (DbType = Guid), @p62='?' (DbType = DateTime2), @p65='?' (DbType = Guid), @p64='?' (DbType = DateTime2), @p67='?' (DbType = Guid), @p66='?' (DbType = DateTime2), @p69='?' (DbType = Guid), @p68='?' (DbType = DateTime2), @p71='?' (DbType = Guid), @p70='?' (DbType = DateTime2), @p73='?' (DbType = Guid), @p72='?' (DbType = DateTime2), @p75='?' (DbType = Guid), @p74='?' (DbType = DateTime2), @p77='?' (DbType = Guid), @p76='?' (DbType = DateTime2), @p79='?' (DbType = Guid), @p78='?' (DbType = DateTime2), @p81='?' (DbType = Guid), @p80='?' (DbType = DateTime2), @p83='?' (DbType = Guid), @p82='?' (DbType = DateTime2), @p85='?' (DbType = Guid), @p84='?' (DbType = DateTime2), @p87='?' (DbType = Guid), @p86='?' (DbType = DateTime2), @p89='?' (DbType = Guid), @p88='?' (DbType = DateTime2), @p91='?' (DbType = Guid), @p90='?' (DbType = DateTime2), @p93='?' (DbType = Guid), @p92='?' (DbType = DateTime2), @p95='?' (DbType = Guid), @p94='?' (DbType = DateTime2), @p97='?' (DbType = Guid), @p96='?' (DbType = DateTime2), @p99='?' (DbType = Guid), @p98='?' (DbType = DateTime2), @p101='?' (DbType = Guid), @p100='?' (DbType = DateTime2), @p103='?' (DbType = Guid), @p102='?' (DbType = DateTime2), @p105='?' (DbType = Guid), @p104='?' (DbType = DateTime2)], CommandType='Text', CommandTimeout='30']
UPDATE tabela_a SET data = @p0
WHERE id = @p1;
UPDATE tabela_a SET data = @p2
WHERE id = @p3;
UPDATE tabela_a SET data = @p4
WHERE id = @p5;
UPDATE tabela_a SET data = @p6
WHERE id = @p7;
UPDATE tabela_a SET data = @p8
WHERE id = @p9;
UPDATE tabela_a SET data = @p10
WHERE id = @p11;
UPDATE tabela_a SET data = @p12
WHERE id = @p13;
UPDATE tabela_a SET data = @p14
WHERE id = @p15;
UPDATE tabela_a SET data = @p16
WHERE id = @p17;
UPDATE tabela_a SET data = @p18
WHERE id = @p19;
UPDATE tabela_a SET data = @p20
WHERE id = @p21;
UPDATE tabela_a SET data = @p22
WHERE id = @p23;
UPDATE tabela_a SET data = @p24
WHERE id = @p25;
UPDATE tabela_a SET data = @p26
WHERE id = @p27;
UPDATE tabela_a SET data = @p28
WHERE id = @p29;
UPDATE tabela_a SET data = @p30
WHERE id = @p31;
UPDATE tabela_a SET data = @p32
WHERE id = @p33;
UPDATE tabela_a SET data = @p34
WHERE id = @p35;
UPDATE tabela_a SET data = @p36
WHERE id = @p37;
UPDATE tabela_a SET data = @p38
WHERE id = @p39;
UPDATE tabela_a SET data = @p40
WHERE id = @p41;
UPDATE tabela_a SET data = @p42
WHERE id = @p43;
UPDATE tabela_a SET data = @p44
WHERE id = @p45;
UPDATE tabela_a SET data = @p46
WHERE id = @p47;
UPDATE tabela_a SET data = @p48
WHERE id = @p49;
UPDATE tabela_a SET data = @p50
WHERE id = @p51;
UPDATE tabela_a SET data = @p52
WHERE id = @p53;
UPDATE tabela_a SET data = @p54
WHERE id = @p55;
UPDATE tabela_a SET data = @p56
WHERE id = @p57;
UPDATE tabela_a SET data = @p58
WHERE id = @p59;
UPDATE tabela_a SET data = @p60
WHERE id = @p61;
UPDATE tabela_a SET data = @p62
WHERE id = @p63;
UPDATE tabela_a SET data = @p64
WHERE id = @p65;
UPDATE tabela_a SET data = @p66
WHERE id = @p67;
UPDATE tabela_a SET data = @p68
WHERE id = @p69;
UPDATE tabela_a SET data = @p70
WHERE id = @p71;
UPDATE tabela_a SET data = @p72
WHERE id = @p73;
UPDATE tabela_a SET data = @p74
WHERE id = @p75;
UPDATE tabela_a SET data = @p76
WHERE id = @p77;
UPDATE tabela_a SET data = @p78
WHERE id = @p79;
UPDATE tabela_a SET data = @p80
WHERE id = @p81;
UPDATE tabela_a SET data = @p82
WHERE id = @p83;
UPDATE tabela_a SET data = @p84
WHERE id = @p85;
UPDATE tabela_a SET data = @p86
WHERE id = @p87;
UPDATE tabela_a SET data = @p88
WHERE id = @p89;
UPDATE tabela_a SET data = @p90
WHERE id = @p91;
UPDATE tabela_a SET data = @p92
WHERE id = @p93;
UPDATE tabela_a SET data = @p94
WHERE id = @p95;
UPDATE tabela_a SET data = @p96
WHERE id = @p97;
UPDATE tabela_a SET data = @p98
WHERE id = @p99;
UPDATE tabela_a SET data = @p100
WHERE id = @p101;
UPDATE tabela_a SET data = @p102
WHERE id = @p103;
UPDATE tabela_a SET data = @p104
WHERE id = @p105;
Registros afetados: 53 - Tempo: 3334 ms
Note que primeiro temos a consulta para buscar os registros e depois temos uma série de comandos UPDATE, um para cada registro que foi alterado. Isso pode gerar uma sobrecarga significativa no banco de dados, especialmente quando lidamos com um grande volume de registros.
Update com Attach e SaveChanges
Outra abordagem é utilizar o método Attach para anexar as entidades ao contexto e depois chamar o SaveChanges. Isso evita a consulta inicial para buscar os registros, mas ainda assim gera um comando UPDATE para cada registro alterado. No exemplo abaixo, utilizamos o AsNoTracking para evitar o rastreamento das entidades, já que não precisamos carregar os dados para o contexto.
Stopwatch sw = new Stopwatch();
sw.Start();
var registros = context.TabelaAs.AsNoTracking()
.Where(x => x.Criacao >= DateTime.Now.AddDays(-30)).ToList();
foreach (var item in registros)
{
item.Data = DateTime.Now;
context.Attach<TabelaA>(item);
context.Entry(item).State = EntityState.Modified;
}
int registrosAfetados = context.SaveChanges();
sw.Stop();
Console.WriteLine($"Registros afetados: {registrosAfetados} - Tempo: {sw.ElapsedMilliseconds} ms");
O log gerado para o Attach foi o seguinte:
info: 11/09/2025 19:08:15.823 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
Executed DbCommand (71ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT t.id, t.booleano, t.criacao, t.data, t.texto
FROM tabela_a AS t
WHERE t.criacao >= now()::timestamp + INTERVAL '-30 days'
info: 11/09/2025 19:08:16.080 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
Executed DbCommand (61ms) [Parameters=[@p4='?' (DbType = Guid), @p0='?' (DbType = Boolean), @p1='?' (DbType = DateTime2), @p2='?' (DbType = DateTime2), @p3='?', @p9='?' (DbType = Guid), @p5='?' (DbType = Boolean), @p6='?' (DbType = DateTime2), @p7='?' (DbType = DateTime2), @p8='?', @p14='?' (DbType = Guid), @p10='?' (DbType = Boolean), @p11='?' (DbType = DateTime2), @p12='?' (DbType = DateTime2), @p13='?', @p19='?' (DbType = Guid), @p15='?' (DbType = Boolean), @p16='?' (DbType = DateTime2), @p17='?' (DbType = DateTime2), @p18='?', @p24='?' (DbType = Guid), @p20='?' (DbType = Boolean), @p21='?' (DbType = DateTime2), @p22='?' (DbType = DateTime2), @p23='?', @p29='?' (DbType = Guid), @p25='?' (DbType = Boolean), @p26='?' (DbType = DateTime2), @p27='?' (DbType = DateTime2), @p28='?', @p34='?' (DbType = Guid), @p30='?' (DbType = Boolean), @p31='?' (DbType = DateTime2), @p32='?' (DbType = DateTime2), @p33='?', @p39='?' (DbType = Guid), @p35='?' (DbType = Boolean), @p36='?' (DbType = DateTime2), @p37='?' (DbType = DateTime2), @p38='?', @p44='?' (DbType = Guid), @p40='?' (DbType = Boolean), @p41='?' (DbType = DateTime2), @p42='?' (DbType = DateTime2), @p43='?', @p49='?' (DbType = Guid), @p45='?' (DbType = Boolean), @p46='?' (DbType = DateTime2), @p47='?' (DbType = DateTime2), @p48='?', @p54='?' (DbType = Guid), @p50='?' (DbType = Boolean), @p51='?' (DbType = DateTime2), @p52='?' (DbType = DateTime2), @p53='?', @p59='?' (DbType = Guid), @p55='?' (DbType = Boolean), @p56='?' (DbType = DateTime2), @p57='?' (DbType = DateTime2), @p58='?', @p64='?' (DbType = Guid), @p60='?' (DbType = Boolean), @p61='?' (DbType = DateTime2), @p62='?' (DbType = DateTime2), @p63='?', @p69='?' (DbType = Guid), @p65='?' (DbType = Boolean), @p66='?' (DbType = DateTime2), @p67='?' (DbType = DateTime2), @p68='?', @p74='?' (DbType = Guid), @p70='?' (DbType = Boolean), @p71='?' (DbType = DateTime2), @p72='?' (DbType = DateTime2), @p73='?', @p79='?' (DbType = Guid), @p75='?' (DbType = Boolean), @p76='?' (DbType = DateTime2), @p77='?' (DbType = DateTime2), @p78='?', @p84='?' (DbType = Guid), @p80='?' (DbType = Boolean), @p81='?' (DbType = DateTime2), @p82='?' (DbType = DateTime2), @p83='?', @p89='?' (DbType = Guid), @p85='?' (DbType = Boolean), @p86='?' (DbType = DateTime2), @p87='?' (DbType = DateTime2), @p88='?', @p94='?' (DbType = Guid), @p90='?' (DbType = Boolean), @p91='?' (DbType = DateTime2), @p92='?' (DbType = DateTime2), @p93='?', @p99='?' (DbType = Guid), @p95='?' (DbType = Boolean), @p96='?' (DbType = DateTime2), @p97='?' (DbType = DateTime2), @p98='?', @p104='?' (DbType = Guid), @p100='?' (DbType = Boolean), @p101='?' (DbType = DateTime2), @p102='?' (DbType = DateTime2), @p103='?', @p109='?' (DbType = Guid), @p105='?' (DbType = Boolean), @p106='?' (DbType = DateTime2), @p107='?' (DbType = DateTime2), @p108='?', @p114='?' (DbType = Guid), @p110='?' (DbType = Boolean), @p111='?' (DbType = DateTime2), @p112='?' (DbType = DateTime2), @p113='?', @p119='?' (DbType = Guid), @p115='?' (DbType = Boolean), @p116='?' (DbType = DateTime2), @p117='?' (DbType = DateTime2), @p118='?', @p124='?' (DbType = Guid), @p120='?' (DbType = Boolean), @p121='?' (DbType = DateTime2), @p122='?' (DbType = DateTime2), @p123='?', @p129='?' (DbType = Guid), @p125='?' (DbType = Boolean), @p126='?' (DbType = DateTime2), @p127='?' (DbType = DateTime2), @p128='?', @p134='?' (DbType = Guid), @p130='?' (DbType = Boolean), @p131='?' (DbType = DateTime2), @p132='?' (DbType = DateTime2), @p133='?', @p139='?' (DbType = Guid), @p135='?' (DbType = Boolean), @p136='?' (DbType = DateTime2), @p137='?' (DbType = DateTime2), @p138='?', @p144='?' (DbType = Guid), @p140='?' (DbType = Boolean), @p141='?' (DbType = DateTime2), @p142='?' (DbType = DateTime2), @p143='?', @p149='?' (DbType = Guid), @p145='?' (DbType = Boolean), @p146='?' (DbType = DateTime2), @p147='?' (DbType = DateTime2), @p148='?', @p154='?' (DbType = Guid), @p150='?' (DbType = Boolean), @p151='?' (DbType = DateTime2), @p152='?' (DbType = DateTime2), @p153='?', @p159='?' (DbType = Guid), @p155='?' (DbType = Boolean), @p156='?' (DbType = DateTime2), @p157='?' (DbType = DateTime2), @p158='?', @p164='?' (DbType = Guid), @p160='?' (DbType = Boolean), @p161='?' (DbType = DateTime2), @p162='?' (DbType = DateTime2), @p163='?', @p169='?' (DbType = Guid), @p165='?' (DbType = Boolean), @p166='?' (DbType = DateTime2), @p167='?' (DbType = DateTime2), @p168='?', @p174='?' (DbType = Guid), @p170='?' (DbType = Boolean), @p171='?' (DbType = DateTime2), @p172='?' (DbType = DateTime2), @p173='?', @p179='?' (DbType = Guid), @p175='?' (DbType = Boolean), @p176='?' (DbType = DateTime2), @p177='?' (DbType = DateTime2), @p178='?', @p184='?' (DbType = Guid), @p180='?' (DbType = Boolean), @p181='?' (DbType = DateTime2), @p182='?' (DbType = DateTime2), @p183='?', @p189='?' (DbType = Guid), @p185='?' (DbType = Boolean), @p186='?' (DbType = DateTime2), @p187='?' (DbType = DateTime2), @p188='?', @p194='?' (DbType = Guid), @p190='?' (DbType = Boolean), @p191='?' (DbType = DateTime2), @p192='?' (DbType = DateTime2), @p193='?', @p199='?' (DbType = Guid), @p195='?' (DbType = Boolean), @p196='?' (DbType = DateTime2), @p197='?' (DbType = DateTime2), @p198='?', @p204='?' (DbType = Guid), @p200='?' (DbType = Boolean), @p201='?' (DbType = DateTime2), @p202='?' (DbType = DateTime2), @p203='?', @p209='?' (DbType = Guid), @p205='?' (DbType = Boolean), @p206='?' (DbType = DateTime2), @p207='?' (DbType = DateTime2), @p208='?', @p214='?' (DbType = Guid), @p210='?' (DbType = Boolean), @p211='?' (DbType = DateTime2), @p212='?' (DbType = DateTime2), @p213='?', @p219='?' (DbType = Guid), @p215='?' (DbType = Boolean), @p216='?' (DbType = DateTime2), @p217='?' (DbType = DateTime2), @p218='?', @p224='?' (DbType = Guid), @p220='?' (DbType = Boolean), @p221='?' (DbType = DateTime2), @p222='?' (DbType = DateTime2), @p223='?', @p229='?' (DbType = Guid), @p225='?' (DbType = Boolean), @p226='?' (DbType = DateTime2), @p227='?' (DbType = DateTime2), @p228='?', @p234='?' (DbType = Guid), @p230='?' (DbType = Boolean), @p231='?' (DbType = DateTime2), @p232='?' (DbType = DateTime2), @p233='?', @p239='?' (DbType = Guid), @p235='?' (DbType = Boolean), @p236='?' (DbType = DateTime2), @p237='?' (DbType = DateTime2), @p238='?', @p244='?' (DbType = Guid), @p240='?' (DbType = Boolean), @p241='?' (DbType = DateTime2), @p242='?' (DbType = DateTime2), @p243='?', @p249='?' (DbType = Guid), @p245='?' (DbType = Boolean), @p246='?' (DbType = DateTime2), @p247='?' (DbType = DateTime2), @p248='?', @p254='?' (DbType = Guid), @p250='?' (DbType = Boolean), @p251='?' (DbType = DateTime2), @p252='?' (DbType = DateTime2), @p253='?', @p259='?' (DbType = Guid), @p255='?' (DbType = Boolean), @p256='?' (DbType = DateTime2), @p257='?' (DbType = DateTime2), @p258='?', @p264='?' (DbType = Guid), @p260='?' (DbType = Boolean), @p261='?' (DbType = DateTime2), @p262='?' (DbType = DateTime2), @p263='?'], CommandType='Text', CommandTimeout='30']
UPDATE tabela_a SET booleano = @p0, criacao = @p1, data = @p2, texto = @p3
WHERE id = @p4;
UPDATE tabela_a SET booleano = @p5, criacao = @p6, data = @p7, texto = @p8
WHERE id = @p9;
UPDATE tabela_a SET booleano = @p10, criacao = @p11, data = @p12, texto = @p13
WHERE id = @p14;
UPDATE tabela_a SET booleano = @p15, criacao = @p16, data = @p17, texto = @p18
WHERE id = @p19;
UPDATE tabela_a SET booleano = @p20, criacao = @p21, data = @p22, texto = @p23
WHERE id = @p24;
UPDATE tabela_a SET booleano = @p25, criacao = @p26, data = @p27, texto = @p28
WHERE id = @p29;
UPDATE tabela_a SET booleano = @p30, criacao = @p31, data = @p32, texto = @p33
WHERE id = @p34;
UPDATE tabela_a SET booleano = @p35, criacao = @p36, data = @p37, texto = @p38
WHERE id = @p39;
UPDATE tabela_a SET booleano = @p40, criacao = @p41, data = @p42, texto = @p43
WHERE id = @p44;
UPDATE tabela_a SET booleano = @p45, criacao = @p46, data = @p47, texto = @p48
WHERE id = @p49;
UPDATE tabela_a SET booleano = @p50, criacao = @p51, data = @p52, texto = @p53
WHERE id = @p54;
UPDATE tabela_a SET booleano = @p55, criacao = @p56, data = @p57, texto = @p58
WHERE id = @p59;
UPDATE tabela_a SET booleano = @p60, criacao = @p61, data = @p62, texto = @p63
WHERE id = @p64;
UPDATE tabela_a SET booleano = @p65, criacao = @p66, data = @p67, texto = @p68
WHERE id = @p69;
UPDATE tabela_a SET booleano = @p70, criacao = @p71, data = @p72, texto = @p73
WHERE id = @p74;
UPDATE tabela_a SET booleano = @p75, criacao = @p76, data = @p77, texto = @p78
WHERE id = @p79;
UPDATE tabela_a SET booleano = @p80, criacao = @p81, data = @p82, texto = @p83
WHERE id = @p84;
UPDATE tabela_a SET booleano = @p85, criacao = @p86, data = @p87, texto = @p88
WHERE id = @p89;
UPDATE tabela_a SET booleano = @p90, criacao = @p91, data = @p92, texto = @p93
WHERE id = @p94;
UPDATE tabela_a SET booleano = @p95, criacao = @p96, data = @p97, texto = @p98
WHERE id = @p99;
UPDATE tabela_a SET booleano = @p100, criacao = @p101, data = @p102, texto = @p103
WHERE id = @p104;
UPDATE tabela_a SET booleano = @p105, criacao = @p106, data = @p107, texto = @p108
WHERE id = @p109;
UPDATE tabela_a SET booleano = @p110, criacao = @p111, data = @p112, texto = @p113
WHERE id = @p114;
UPDATE tabela_a SET booleano = @p115, criacao = @p116, data = @p117, texto = @p118
WHERE id = @p119;
UPDATE tabela_a SET booleano = @p120, criacao = @p121, data = @p122, texto = @p123
WHERE id = @p124;
UPDATE tabela_a SET booleano = @p125, criacao = @p126, data = @p127, texto = @p128
WHERE id = @p129;
UPDATE tabela_a SET booleano = @p130, criacao = @p131, data = @p132, texto = @p133
WHERE id = @p134;
UPDATE tabela_a SET booleano = @p135, criacao = @p136, data = @p137, texto = @p138
WHERE id = @p139;
UPDATE tabela_a SET booleano = @p140, criacao = @p141, data = @p142, texto = @p143
WHERE id = @p144;
UPDATE tabela_a SET booleano = @p145, criacao = @p146, data = @p147, texto = @p148
WHERE id = @p149;
UPDATE tabela_a SET booleano = @p150, criacao = @p151, data = @p152, texto = @p153
WHERE id = @p154;
UPDATE tabela_a SET booleano = @p155, criacao = @p156, data = @p157, texto = @p158
WHERE id = @p159;
UPDATE tabela_a SET booleano = @p160, criacao = @p161, data = @p162, texto = @p163
WHERE id = @p164;
UPDATE tabela_a SET booleano = @p165, criacao = @p166, data = @p167, texto = @p168
WHERE id = @p169;
UPDATE tabela_a SET booleano = @p170, criacao = @p171, data = @p172, texto = @p173
WHERE id = @p174;
UPDATE tabela_a SET booleano = @p175, criacao = @p176, data = @p177, texto = @p178
WHERE id = @p179;
UPDATE tabela_a SET booleano = @p180, criacao = @p181, data = @p182, texto = @p183
WHERE id = @p184;
UPDATE tabela_a SET booleano = @p185, criacao = @p186, data = @p187, texto = @p188
WHERE id = @p189;
UPDATE tabela_a SET booleano = @p190, criacao = @p191, data = @p192, texto = @p193
WHERE id = @p194;
UPDATE tabela_a SET booleano = @p195, criacao = @p196, data = @p197, texto = @p198
WHERE id = @p199;
UPDATE tabela_a SET booleano = @p200, criacao = @p201, data = @p202, texto = @p203
WHERE id = @p204;
UPDATE tabela_a SET booleano = @p205, criacao = @p206, data = @p207, texto = @p208
WHERE id = @p209;
UPDATE tabela_a SET booleano = @p210, criacao = @p211, data = @p212, texto = @p2136
WHERE id = @p214;
UPDATE tabela_a SET booleano = @p215, criacao = @p216, data = @p217, texto = @p218
WHERE id = @p219;
UPDATE tabela_a SET booleano = @p220, criacao = @p221, data = @p222, texto = @p223
WHERE id = @p224;
UPDATE tabela_a SET booleano = @p225, criacao = @p226, data = @p227, texto = @p228
WHERE id = @p229;
UPDATE tabela_a SET booleano = @p230, criacao = @p231, data = @p232, texto = @p233
WHERE id = @p234;
UPDATE tabela_a SET booleano = @p235, criacao = @p236, data = @p237, texto = @p238
WHERE id = @p239;
UPDATE tabela_a SET booleano = @p240, criacao = @p241, data = @p242, texto = @p243
WHERE id = @p244;
UPDATE tabela_a SET booleano = @p245, criacao = @p246, data = @p247, texto = @p248
WHERE id = @p249;
UPDATE tabela_a SET booleano = @p250, criacao = @p251, data = @p252, texto = @p253
WHERE id = @p254;
UPDATE tabela_a SET booleano = @p255, criacao = @p256, data = @p257, texto = @p258
WHERE id = @p259;
UPDATE tabela_a SET booleano = @p260, criacao = @p261, data = @p262, texto = @p263
WHERE id = @p264;
Registros afetados: 53 - Tempo: 2598 ms
Nesse caso também são gerados múltiplos comandos UPDATE, para cada registro alterado, mas tem um detalhe a mais, temos a atualização de todos os campos da entidade, mesmo que apenas um campo tenha sido alterado. Além de gerar mais carga no banco de dados, isso pode levar a outros como perdermos dados se houverem outras alterações concorrentes, ou se o objeto não estiver completamente preenchido.
Update utilizando ExecuteUpdate
A partir do Entity Framework Core 7, temos o método ExecuteUpdate, que permite realizar atualizações em massa diretamente no banco de dados, gerando um único comando UPDATE. Isso é muito mais eficiente quando precisamos atualizar vários registros.
Stopwatch sw = new Stopwatch();
sw.Start();
int registrosAfetados = context.TabelaAs
.Where(x=>x.Criacao >= DateTime.Now.AddDays(-30))
.ExecuteUpdate(p => p.SetProperty( x=>x.Data, DateTime.Now));
context.SaveChanges();
sw.Stop();
Console.WriteLine($"Registros afetados: {registrosAfetados} - Tempo: {sw.ElapsedMilliseconds} ms");
O log gerado para o ExecuteUpdate foi o seguinte:
info: 11/09/2025 22:54:32.343 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
Executed DbCommand (61ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
UPDATE tabela_a AS t
SET data = now()::timestamp
WHERE t.criacao >= now()::timestamp + INTERVAL '-30 days'
Registros afetados: 53 - Tempo: 2368 ms
Como podemos ver, nesse caso é gerado apenas um comando UPDATE, que atualiza todos os registros que atendem à condição e apenas os campos necessários, isso reduz significativamente a carga no banco de dados e melhora o desempenho da aplicação.
Conclusão
Cada abordagem tem sua vantagem, o ExecuteUpdate é a mais eficiente quando precisamos atualizar vários registros, pois gera um único comando UPDATE no banco de dados. Já o Attach pode ser útil quando precisamos atualizar registros específicos e já temos as entidades carregadas, mas ainda assim gera múltiplos comandos UPDATE. A abordagem tradicional de buscar os registros, alterar e salvar deve ser evitada em cenários de atualização em massa, mas ela ainda é válida para atualizações pontuais onde o número de registros é pequeno.
Vale ressaltar que tanto o Attach quanto o ExecuteUpdate não necessitam de uma consulta inicial ou que os registros estejam sendo rastreados pelo contexto, o que é uma vantagem em termos de desempenho e uso de memória.
Repositório
Confira o código completo no meu repositório no GitHub
