Skip to the content.
Skip to the content.

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:

copy
[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.

copy
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:

copy
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.

copy
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:

copy
 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.

copy
 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:

copy
 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