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!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
This was lovelyy to read