Журнал аудита: веб-приложение

Я работаю над проектом контрольного следа, за которым нам сказали следовать.

Отслеживайте все таблицы (200+) в нашей базе данных с теневыми таблицами, как это делает Hibernate Envers. Из этого следует, что мы создали снимок для каждой транзакции с участием CUD.

В прошлом я реализовал решения для аудита конечных наборов важных данных для каждого из моих клиентов. По текущей работе мои вопросы:

  1. Есть ли смысл проверять каждую таблицу в базе данных?
  2. Насколько ценно было бы отслеживать данные, как это делает Энверс? Любое приложение хотело бы иметь дельты для определенных точек данных. Запросы огромных наборов данных для определения дельт кажутся нереалистичными.
  3. Решение, подобное Envers, требует связывания действий CUD с транзакцией, эффективно исключая триггеры. Это связано с тем, что триггеры запускаются в своих собственных транзакциях, и, следовательно, данные в теневых таблицах могут не синхронизироваться в случае отката транзакции из приложения. Что-нибудь, что мне здесь не хватает?
  4. Кто-нибудь предлагает использовать базы данных NoSQL для аудита?

person user483576    schedule 08.11.2010    source источник


Ответы (2)


Полностью реализован и может быть улучшен еще. Надеюсь, это может кому-то помочь:

public partial  class Entity:DbContext
    {

      public enum AuditActions {I,U,D}

      public override int SaveChanges( )
      {
          ChangeTracker.DetectChanges(); 
          ObjectContext ctx = ((IObjectContextAdapter)this).ObjectContext;
          // string UserName = WindowsIdentity.GetCurrent().Name;
          IPrincipal principal = Thread.CurrentPrincipal;
          IIdentity identity = principal == null ? null : principal.Identity;
          string name = identity == null ? "" : identity.Name;

          //Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity((userName), roles);
          List<ObjectStateEntry> objectStateEntryList =
              ctx.ObjectStateManager.GetObjectStateEntries(EntityState.Added
                                                         | EntityState.Modified
                                                         | EntityState.Deleted)
              .ToList();

          List<DBAudit> AuditList = new List<DBAudit>();

          string Audittable = string.Empty; 
          foreach (ObjectStateEntry entry in objectStateEntryList)
          {
               Audittable = entry.EntitySet.ToString();

               if (!entry.IsRelationship && Audittable!="Audit table name")
              {

                  //sIsAuditTble =entry.EntitySet="DBAudit"? true:false;
                  switch (entry.State)
                  {
                      case EntityState.Added:
                        AuditList=  LogDetails(entry, name, AuditActions.I);
                          break;
                      case EntityState.Deleted:
                        AuditList=  LogDetails(entry, name, AuditActions.D);
                          break;
                      case EntityState.Modified:
                        AuditList=  LogDetails(entry, name, AuditActions.U);
                           break;

                  }
              }
          }



              using (var context = new ProjectTrackerEntities())
              {
                  for (int i = 0; i < AuditList.Count; i++)
                  {
                      context.DBAudits.Add(AuditList[i]);
                      context.SaveChanges();
                  }
              }

          return base.SaveChanges();
      }

      public List<DBAudit> LogDetails(ObjectStateEntry entry, string UserName, AuditActions action)
      {
          List<DBAudit> dbAuditList = new List<DBAudit>();

        if (action == AuditActions.I)
          {

              var keyValues = new Dictionary<string, object>();
              var currentValues = entry.CurrentValues;

             // entry.Entity key = new EntityKey();

                  DBAudit audit = new DBAudit();
                  audit.AuditId = Guid.NewGuid().ToString();
                  audit.RevisionStamp = DateTime.Now;
                  audit.TableName = entry.EntitySet.Name;
                  audit.UserName = UserName;
                  audit.OldData = "";
                  audit.Actions = action.ToString();
                  for (int i = 0; i < currentValues.FieldCount; i++)
                  {
                  audit.ChangedColumns = audit.ChangedColumns + currentValues.GetName(i);
                  audit.NewData = audit.NewData + currentValues.GetValue(i);
                  audit.ChangedColumns = audit.ChangedColumns + ", ";
                  audit.NewData = audit.NewData + ", ";
                  }
                  dbAuditList.Add(audit);
                  //LogSave(audit);




          }
          else if (action == AuditActions.D)
          {
              var keyValues = new Dictionary<string, object>();
              var DeletedValues = entry.OriginalValues;

              // entry.Entity key = new EntityKey();


              DBAudit audit = new DBAudit();
              audit.AuditId = Guid.NewGuid().ToString();
              audit.RevisionStamp = DateTime.Now;
              audit.TableName = entry.EntitySet.Name;
              audit.UserName = UserName;
              audit.NewData = "";

              audit.Actions = action.ToString();
              for (int i = 0; i < DeletedValues.FieldCount; i++)
              {
                  audit.ChangedColumns = audit.ChangedColumns + DeletedValues.GetName(i);
                  audit.OldData = audit.OldData + DeletedValues.GetValue(i);
                  audit.ChangedColumns = audit.ChangedColumns + ", ";
                  audit.OldData = audit.OldData + ", ";
              }
              dbAuditList.Add(audit);
          }
          else 
          {

                  foreach (string propertyName in entry.GetModifiedProperties())
                  {
                      DBAudit audit = new DBAudit();
                      DbDataRecord original = entry.OriginalValues;
                      string oldValue = original.GetValue(original.GetOrdinal(propertyName)).ToString();

                      CurrentValueRecord current = entry.CurrentValues;
                      string newValue = current.GetValue(current.GetOrdinal(propertyName)).ToString();

                      audit.AuditId = Guid.NewGuid().ToString();
                      audit.RevisionStamp = DateTime.Now;
                      audit.TableName = entry.EntitySet.Name;
                      audit.UserName = UserName;
                      audit.ChangedColumns = propertyName;
                      audit.OldData = oldValue;
                      audit.NewData = newValue;
                      audit.Actions = action.ToString();
                      dbAuditList.Add(audit);
                      //LogSave(audit);


                    }

          }

        return dbAuditList;


      }



    }
person murali    schedule 19.12.2012
comment
Добро пожаловать на SO, это хорошая практика - объяснить, зачем использовать ваше решение, а не только как. Это сделает ваш ответ более ценным и поможет дальнейшему читателю лучше понять, как вы это делаете. Я также предлагаю вам ознакомиться с нашими часто задаваемыми вопросами: stackoverflow.com/faq. - person ForceMagic; 19.12.2012

Одним из вариантов для базы данных NoSQL является RavenDB, использующий его "пакет управления версиями".

Хотя сейчас, вероятно, еще слишком рано, я недавно слушал интересный эпизод кода Хердинга, где они разговаривают с Эриком Синком на о правдивости. Насколько я понимаю, Veracity является частично распределенной системой контроля версий и частично базой данных NoSQL. Он предназначен для использования в качестве серверной части всего, от системы управления версиями до вики. Он находится в разработке в течение пары лет, но все еще находится на стадии предварительной бета-версии (по состоянию на ноябрь 2010 г.).

person gregmac    schedule 08.11.2010
comment
Для достоверности я не уверен, что это возможно: veracity-scm.com/qa/questions/545/ - person gpasse; 09.01.2012