28 votes

Implémentation du journal d'audit / de l'historique des modifications avec MVC et Entity Framework

Je suis bâtiment dans un, Changer l'Histoire / Journal d'Audit pour mon MVC application qui est à l'aide de Entity Framework.

Donc, précisément dans la méthode edit public ActionResult Edit(ViewModel vm), nous trouvons l'objet que nous essayons de mettre à jour, et ensuite utiliser TryUpdateModel(object) de transposer les valeurs de la forme à l'objet que nous essayons de mettre à jour.

Je veux connecter un changement quand tout le champ de l'objet de modifications. Donc, fondamentalement, ce que j'ai besoin d'une copie de l'objet avant de l'éditer et de le comparer après l' TryUpdateModel(object) a fait son travail. c'est à dire

[HttpPost]
public ActionResult Edit(ViewModel vm)
{
    //Need to take the copy here
    var object = EntityFramework.Object.Single(x=>x.ID = vm.ID);

    if (ModelState.IsValid)
    {
        //Form the un edited view model
        var uneditedVM = BuildViewModel(vm.ID); //this line seems to confuse the EntityFramework (BuildViewModel() is used to build the model when originally displaying the form)
        //Compare with old view model
        WriteChanges(uneditedVM, vm);
        ...
        TryUpdateModel(object);
    }
    ...
}

Mais le problème, c'est quand le code récupère les "inédits vm", c'est à l'origine de certains changements inattendus dans le EntityFramework - de sorte qu' TryUpdateModel(object); jette un UpdateException.

La question est donc dans cette situation - comment puis-je créer une copie de l' object à l'extérieur de EntityFramework de comparer pour le changement/l'historique d'audit, de manière à ne pas affecter ou modifier l' EntityFramework à tous

edit: Ne voulez pas utiliser des déclencheurs. Besoin d'enregistrer le nom de l'utilisateur qui l'a fait.

edit1: à l'Aide de EFv4, pas trop sûr de la façon d'aller sur la substitution SaveChanges() , mais il peut être une option


Cette route semble aller nulle part, pour une simple exigence! J'ai finalement réussi à le remplacer correctement, mais maintenant, je reçois une exception avec ce code:

public partial class Entities
{
    public override int SaveChanges(SaveOptions options)
    {
        DetectChanges();
        var modifiedEntities = ObjectStateManager.GetObjectStateEntries(EntityState.Modified);
        foreach (var entry in modifiedEntities)
        {
            var modifiedProps = ObjectStateManager.GetObjectStateEntry(entry).GetModifiedProperties(); //This line throws exception The ObjectStateManager does not contain an ObjectStateEntry with a reference to an object of type 'System.Data.Objects.EntityEntry'.
            var currentValues = ObjectStateManager.GetObjectStateEntry(entry).CurrentValues;
            foreach (var propName in modifiedProps)
            {
                var newValue = currentValues[propName];
                //log changes
            }
        }

        //return base.SaveChanges();
        return base.SaveChanges(options);
    }
}

18voto

Eranga Points 21853

SI vous utilisez EF 4 vous pouvez vous abonner à l' SavingChanges événement.

Depuis Entities est une classe partielle vous pouvez ajouter des fonctionnalités supplémentaires dans un fichier séparé. Donc, créez un nouveau fichier nommé Entities et il y en œuvre partielle de la méthode de OnContextCreated de crochet de l'événement

public partial class Entities
{
    partial void OnContextCreated()
    {
        SavingChanges += OnSavingChanges;
    }

    void OnSavingChanges(object sender, EventArgs e)
    {

        var modifiedEntities = ObjectStateManager.GetObjectStateEntries(EntityState.Modified);
        foreach (var entry in modifiedEntities)
        {
            var modifiedProps = ObjectStateManager.GetObjectStateEntry(entry.EntityKey).GetModifiedProperties();
            var currentValues = ObjectStateManager.GetObjectStateEntry(entry.EntityKey).CurrentValues;
            foreach (var propName in modifiedProps)
            {
                var newValue = currentValues[propName];
                //log changes
            }
        }
    }
}

Si vous utilisez EF 4.1, vous pouvez passer par cet article pour extraire les modifications

15voto

Martin Eden Points 1432

Voir FrameLog, une Entité Cadre de la journalisation de la bibliothèque que j'ai écrit à cette fin. Il est open-source, y compris pour un usage commercial.

Je sais que vous préférez viens de voir un extrait de code montrant comment le faire, mais de traiter correctement tous les cas pour l'exploitation forestière, y compris la relation changements et plusieurs-à-plusieurs modifications, le code devient assez grand. J'espère que la bibliothèque sera un bon choix pour vos besoins, mais si vous pouvez librement adapter le code.

FrameLog pouvez le journal des modifications à tous les scalaires et les propriétés de navigation, et vous permet également de spécifier un sous-ensemble de ce que vous êtes intéressé dans l'exploitation forestière.

1voto

Patrik Lindström Points 382

Il y a un article avec une note élevée ici sur le projet de code: Implémentation d'Audit Trail en utilisant Entity Framework . Il semble faire ce que tu veux. J'ai commencé à utiliser cette solution dans un projet. J'ai d'abord écrit des déclencheurs en T-SQL dans la base de données mais il était trop difficile de les maintenir avec des changements dans le modèle objet qui se produisaient tout le temps.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X