Контрольный журнал: веб-приложение - PullRequest
5 голосов
/ 08 ноября 2010

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

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

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

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

Ответы [ 2 ]

1 голос
/ 19 декабря 2012

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

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;


      }



    }
0 голосов
/ 08 ноября 2010

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

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

...