2010-04-06 2 views
2

J'ai un modèle d'entité qui a des informations d'audit sur toutes les tables (50+ tables)Étendre le type de base et mettre à jour automatiquement les informations d'audit sur l'entité

CreateDate 
CreateUser 
UpdateDate 
UpdateUser 

Actuellement nous informations d'audit mise à jour programatically.

Ex:

if(changed){ 
     entity.UpdatedOn = DateTime.Now; 
     entity.UpdatedBy = Environment.UserName; 
     context.SaveChanges(); 
    } 

Mais je suis à la recherche d'une solution plus automatisée. Au cours des sauvegardes, si une entité est créée/mise à jour, je voudrais mettre à jour automatiquement ces champs avant de les envoyer à la base de données pour le stockage.

Toute suggestion sur la façon dont je pourrais le faire? Je préférerais ne faire aucune réflexion, donc l'utilisation d'un modèle de texte n'est pas hors de question.

Une solution a été proposée pour surcharger SaveChanges et le faire là, mais pour ce faire je devrais soit utiliser la réflexion (dans laquelle je ne veux pas faire) ou dériver une classe de base. En supposant que je descends cette route, comment pourrais-je y parvenir?

Par exemple

EXAMPLE_DB_TABLE 
CODE 
NAME 
--Audit Tables 
CREATE_DATE 
CREATE_USER 
UPDATE_DATE 
UPDATE_USER 

Et si je crée une classe de base

public abstract class IUpdatable{ 

    public virtual DateTime CreateDate {set;} 
    public virtual string CreateUser { set;} 
    public virtual DateTime UpdateDate { set;} 
    public virtual string UpdateUser { set;} 
} 

L'objectif final est de pouvoir faire quelque chose comme ...

public overrride void SaveChanges(){ 
     //Go through state manager and update audit infromation 
     //FOREACH changed entity in state manager 
     if(entity is IUpdatable){ 
      //If state is created... update create audit. 
      //if state is updated... update update audit 
     } 
    } 

Mais je Je ne suis pas sûr de savoir comment je vais générer le code qui permettrait d'étendre l'interface.

+0

Ce n'est pas vraiment une réponse directe, mais j'ai fait quelque chose de similaire avec LINQ to SQL. Consultez mon article http://farm-fresh-code.blogspot.com/2009/05/auditing-inserts-and-updates-using-linq.html. Cela pourrait vous donner quelques idées. L'idée de base est d'étendre le contexte de données et de surcharger SubmitChanges et d'y effectuer le travail d'audit. Mes informations d'audit sont stockées dans une table différente et je vérifie à la fois le succès et l'échec de sorte qu'il utilise un contexte distinct, mais vous pouvez toujours en avoir quelques idées. – tvanfosson

+0

Merci. Je cherchais à faire des trucs générateurs de code en utilisant des fichiers .tt, mais j'espérais quelque chose de plus simple, je le lirais mal ce soir et je reviendrais vers vous. – Nix

Répondre

1

ici était la solution finale.

Je vérifie essentiellement mon modèle pour la présence de 4 propriétés. Si l'entité contient

InsertedOn et InsertedBy et UpdatedOn et UpdatedBy Je génère (en utilisant un fichier tt) l'entité suivante qui implémente une interface IAuditable.

public interface IAuditable 
{ 
    void SetInsertedOn(DateTime date); 
    void SetInsertedBy(string user); 
    void SetUpdatedOn(DateTime date); 
    void SetUpdatedBy(string user); 
} 

public partial class ExampleDBtable: EntityObject, Audit.IAuditable 
{ 
    //Normal EDMX stuff here.. 
    public static ExampleDBtable CreateExampleDBtable(int id, string code, string name, DateTime insertedOn, string insertedBy, DateTime updatedOn, string updatedBy) 
     { 

     } 
     //Extension points. 
    #region IAuditable Members 

    public void SetInsertedOn(DateTime date) 
    { 
     this._InsertedOn = date; 
    } 

    public void SetInsertedBy(string user) 
    { 
     this._InsertedBy = user; 
    } 

    public void SetUpdatedOn(DateTime date) 
    { 
     this._UpdatedOn = date; 
    } 

    public void SetUpdatedBy(string user) 
    { 
     this._UpdatedBy = user; 
    } 

    #endregion 

    } 

Je produis également du code pour gérer la mise à jour des informations d'audit

public ExampleDBObjectContext(string connectionString) : base(connectionString, "publicExampleDBObjectContext") 
    { 
     this.SavingChanges += new EventHandler(UpdateAuditInformation); 
     this.OnContextCreated(); 
    } 

Et puis finalement je mis à exécution les UpdateAuditInformation

foreach (ObjectStateEntry entry in 
      context.ObjectStateManager.GetObjectStateEntries(
      EntityState.Added | EntityState.Modified)) 
     { 
       //Start pseudo code.. 
       if(entry.Entity is IAuditable){ 
       IAuditable temp = entry.Entity as IAuditable; 
       temp.SetInsertedOn(DateTime.Now); 
       temp.SetInsertedBy(Env.GetUser()); 
       ... 

       } 
     } 

Je choisi de ne pas afficher le fichier .tt parce qu'il semble horrible dans l'éditeur.

0

Oui, je pense que vous pouvez faire quelque chose comme ça. L'idée générale serait

  1. Poignée ObjectContext.SavingChanges.
  2. Dans cet événement, appelez ObjectContext.ObjectStateManager.GetObjectStateEntries (EntityState.Modified)
  3. itérez les résultats et définissez les propriétés si nécessaire.
+0

"Itérer les résultats et définir les propriétés si nécessaire." me fait peur ... vous suggérant une réflexion? – Nix

+0

Non, je ne le suis pas. Parcourez chaque entité modifiée et regardez son type. Si c'est celui que vous voulez auditer, définissez 'entity.UpdatedOn', etc. –

+0

À moins que toutes ces fonctions étendent une interface, vous devrez réfléchir? – Nix

0

Regardez à PostSharp. Très belle solution pour de telles tâches.

+0

toute chance que vous pourriez me donner un peu plus ... je devine l'idée est que je tag mes propriétés avec des attributs de trace>? – Nix

+0

Oui. Désolé, n'a pas vu votre question. Il est possible de définir un trait d'union Trace à l'échelle de l'ensemble. –

+0

Oui, c'est vrai. Il n'y a pas d'échantillon sur cela, seulement du texte qui pourrait être utilisé pour cela. – Marty

0

est-il pas plus simple de « timbre » les lignes mises à jour via des déclencheurs de base de données? Les informations fournies dans la base de données ne sont-elles pas suffisantes? (Utilisateur de base de données par rapport à l'utilisateur os)

+0

nous ne pouvons pas obtenir le bon utilisateur, nous le tirons du contexte d'appel, ou nous utiliserions des déclencheurs. – Nix

Questions connexes