Olá,
Um cenário bastante comum, que encontro nos fóruns, é a necessidade de registrar alguma informação na entidade antes dela ser salva na base de dados, via Entity Framework.
Dados como: “data de inclusão”, “data da última atualização”, “registro de log”, “usuário que realizou a alteração” e outros, são dados pertinentes para o funcionamento da aplicação e que estão atrelados ao evento de inclusão e atualização dos dados na base de dados.
Vamos propor um exemplo: supondo que temos de gravar documentos em nossa base de dados e temos de registrar informações sobre a data de inclusão e data da última alteração do documento.
Propomos então que a estrutura de nossa classe de documentos tem a seguinte estrutura:
public class Document { public int Id { get; set; } public string Title { get; set; } public DateTime CreationTime { get; set; } public DateTime LastUpdate { get; set; } public byte[] Content { get; set; } }
E nossa classe de contexto com o banco de dados contém o seguinte código:
public class DataContext : DbContext { public DbSet<Document> Documents { get; set; } public DataContext() { Database.SetInitializer<DataContext>(new DropCreateDatabaseIfModelChanges<DataContext>()); } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Configurations.Add<Document>(new DocumentConfiguration()); base.OnModelCreating(modelBuilder); } public override int SaveChanges() { // Detecta as alterações efetuadas sobre as entidades this.ChangeTracker.DetectChanges(); // Identifica as instâncias de 'Document' existentes // dentro do ChangeTracker var documents = ChangeTracker.Entries<Document>(); if (documents != null) { // Varre os 'Documents' existentes no ChangeTracker foreach (DbEntityEntry<Document> item in documents) { // Verifica o estado do item switch (item.State) { case EntityState.Added: item.Entity.LastUpdate = item.Entity.CreationTime = DateTime.Now; break; case EntityState.Modified: item.Entity.LastUpdate = DateTime.Now; break; } } } // Realiza a gravação dos itens na base de dados return base.SaveChanges(); } }
Notemos então que nossa classe de contexto com o banco de dados sobrescreve o método “SaveChanges()” e adiciona uma lógica própria para identificação de possíveis instâncias de documentos existentes no ChangeTracker. O ChangeTracker é um pool que acumula todas as instâncias que sofreram alguma alteração, seja ela uma inclusão, modificação ou exclusão.
Note que dentro desta lógica identificamos qual o estado de nossa instância (Added ou Modified) e atribuímos a data corrente as propriedades LastUpdate e CreationTime conforme necessário.
Para testar o funcionamento de nossa lógica, montei o bloco de código abaixo:
class Program { static void Main(string[] args) { using (DataContext context = new DataContext()) { Document newDocument = new Document(); newDocument.Title = "Document 1"; context.Documents.Add(newDocument); context.SaveChanges(); newDocument.Title = "Document 1*"; context.SaveChanges(); } } }
Este post foi bastante simples, mas responde a muitas dúvidas que surgem nos fóruns.
Espero que seja útil
Por
Msc. Fernando Henrique Inocêncio Borba Ferreira
Microsoft Most Valuable Professional – Data Platform Development
Muito bom. Ficaria melhor ainda se utilizar uma interface nas entidades, assim o SaveChanges verifica se a classe implementa a interface e entao aplica a atualizacao de data/hora, ao inves de escrever codigo para cada entidade.
Olá Jone!
Tudo beleza?
Excelente sugestão!!!
Obrigado por comentar!
[]s!
AudtibleContext.cs
hosted with ❤ by GitHub
Parabéns pelo post, Fernando! Eu particularmente eu tenho uma entidade base onde fica minha chave primária e minhas propriedades de data de atualização e criação
Grande Yan!
Sim! Usar classes base com os atributos básicos para cada entidade são uma vantagem dos ORMs.
Outro ponto vantajoso é o uso de rotinas de log das entidades. Este é o ponto perfeito para a inclusão de lógicas deste tipo.
[]s e obrigado por postar!
Dúvida que anda me perseguindo……
Quando damos o override no SaveChanges nós já temos o ID da entidade que esta sendo incluída ou esse ID somente depois do SaveChanges??
Olá, Waldemir.
O padrão é o ID ser gerado apenas depois do SaveChanges.
Quem gera esse valor é o banco de dados se você adotar o comportamento padrão de IDs com autonumeração.
Se você desligar a autonumeração da sua entidade, você será o responsável por manter esse ID e então estará livre para fazer do seu modo e ter o valor antes do SaveChanges.
Pois é.. Verifiquei isso hoje, apesar de não entender o porque isso ocorre e por vezes vamos salvar algo e no meio do caminho cancelamos e quando vemos o próximo registro criado ele pula o ID seguinte da mesma forma, como se tivesse registrado e depois cancelado…..
De qualquer forma muito obrigado pela resposta e tempo.