如何在实体框架 5 中使用 Attribute.IsDefined



我正在使用实体框架来创建审计跟踪。 与其审核每个属性,我想我会创建一个自定义属性

  [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
    public class DoNotAudit : Attribute
    {
    }

然后我会把它应用到我的模型中

 [Table("AuditZone")]
    public class AuditZone
    {
        public AuditZone()
        {
            AuditZoneUploadedCOESDetails = new List<UploadedCOESDetails>();
            AuditZonePostcode = new List<Postcodes>();
        }
        [Key]
        public int Id { get; set; }
        public string Description { get; set; }     
        public bool Valid { get; set; }       
        public DateTime CreatedDate { get; set; }
        public int? CreatedBy { get; set; }
        [DoNotAudit]
        public DateTime? ModifiedDate { get; set; }
        public int? ModifiedBy { get; set; }
        public virtual UserProfile CreatedByUser { get; set; }
        public virtual UserProfile ModifiedByUser { get; set; }
        public virtual ICollection<UploadedCOESDetails> AuditZoneUploadedCOESDetails { get; set; }
        public virtual ICollection<Postcodes> AuditZonePostcode { get; set; }
    }

然后在我的代码中进行审计跟踪

  // This is overridden to prevent someone from calling SaveChanges without specifying the user making the change
        public override int SaveChanges()
        {
            throw new InvalidOperationException("User ID must be provided");
        }
        public int SaveChanges(int userId)
        {
            // Get all Added/Deleted/Modified entities (not Unmodified or Detached)
            foreach (var ent in this.ChangeTracker.Entries().Where(p => p.State == System.Data.EntityState.Added || p.State == System.Data.EntityState.Deleted || p.State == System.Data.EntityState.Modified))
            {
                // For each changed record, get the audit record entries and add them
                foreach (AuditLog x in GetAuditRecordsForChange(ent, userId))
                {
                    this.AuditLogs.Add(x);
                }
            }
            // Call the original SaveChanges(), which will save both the changes made and the audit records
            return base.SaveChanges();
        }
        private List<AuditLog> GetAuditRecordsForChange(DbEntityEntry dbEntry, int userId)
        {
            List<AuditLog> result = new List<AuditLog>();
            DateTime changeTime = DateTime.UtcNow;
            // Get the Table() attribute, if one exists
            //TableAttribute tableAttr = dbEntry.Entity.GetType().GetCustomAttributes(typeof(TableAttribute), false).SingleOrDefault() as TableAttribute;
            TableAttribute tableAttr = dbEntry.Entity.GetType().GetCustomAttributes(typeof(TableAttribute), true).SingleOrDefault() as TableAttribute;
            // Get table name (if it has a Table attribute, use that, otherwise get the pluralized name)
            string tableName = tableAttr != null ? tableAttr.Name : dbEntry.Entity.GetType().Name;
            // Get primary key value (If you have more than one key column, this will need to be adjusted)
            var keyNames = dbEntry.Entity.GetType().GetProperties().Where(p => p.GetCustomAttributes(typeof(KeyAttribute), false).Count() > 0).ToList();
            string keyName = keyNames[0].Name;
            var test = dbEntry.Entity.GetType().GetProperties().Where(p => p.GetCustomAttributes(typeof(DoNotAudit), false).Count() > 0).ToList();

            // //dbEntry.Entity.GetType().GetProperties().Single(p => p.GetCustomAttributes(typeof(KeyAttribute), false).Count() > 0).Name;
            if (dbEntry.State == System.Data.EntityState.Added)
            {
                // For Inserts, just add the whole record
                // If the entity implements IDescribableEntity, use the description from Describe(), otherwise use ToString()
                foreach (string propertyName in dbEntry.CurrentValues.PropertyNames)
                {

                    result.Add(new AuditLog()
                    {
                        AuditLogId = Guid.NewGuid(),
                        UserId = userId,
                        EventDateUTC = changeTime,
                        EventType = "A",    // Added
                        TableName = tableName,
                        RecordId = dbEntry.CurrentValues.GetValue<object>(keyName).ToString(),
                        ColumnName = propertyName,
                        NewValue = dbEntry.CurrentValues.GetValue<object>(propertyName) == null ? null : dbEntry.CurrentValues.GetValue<object>(propertyName).ToString()
                    }
                            );
                }
            }
            else if (dbEntry.State == System.Data.EntityState.Deleted)
            {
                // Same with deletes, do the whole record, and use either the description from Describe() or ToString()
                result.Add(new AuditLog()
                {
                    AuditLogId = Guid.NewGuid(),
                    UserId = userId,
                    EventDateUTC = changeTime,
                    EventType = "D", // Deleted
                    TableName = tableName,
                    RecordId = dbEntry.OriginalValues.GetValue<object>(keyName).ToString(),
                    ColumnName = "*ALL"//,
                   // NewValue = (dbEntry.OriginalValues.ToObject() is IDescribableEntity) ? (dbEntry.OriginalValues.ToObject() as IDescribableEntity).Describe() : dbEntry.OriginalValues.ToObject().ToString()
                }
                    );
            }
            else if (dbEntry.State == System.Data.EntityState.Modified)
            {
                foreach (string propertyName in dbEntry.OriginalValues.PropertyNames)
                {
                    var doNotAUditDefined = dbEntry.Property(propertyName).GetType().GetCustomAttributes(typeof(DoNotAudit), false);
                   // var test1 = dbEntry.Property(propertyName).GetType().Where(p => p.GetCustomAttributes(typeof(DoNotAudit), false).Count() > 0).ToList();
                //    var test = dbEntry.Entity.GetType().GetProperties().Where(p => p.GetCustomAttributes(typeof(DoNotAudit), false).Count() > 0).ToList();

                    // For updates, we only want to capture the columns that actually changed
                    if (!object.Equals(dbEntry.OriginalValues.GetValue<object>(propertyName), dbEntry.CurrentValues.GetValue<object>(propertyName)))
                    {
                        result.Add(new AuditLog()
                        {
                            AuditLogId = Guid.NewGuid(),
                            UserId = userId,
                            EventDateUTC = changeTime,
                            EventType = "M",    // Modified
                            TableName = tableName,
                            RecordId = dbEntry.OriginalValues.GetValue<object>(keyName).ToString(),
                            ColumnName = propertyName,
                            OriginalValue = dbEntry.OriginalValues.GetValue<object>(propertyName) == null ? null : dbEntry.OriginalValues.GetValue<object>(propertyName).ToString(),
                            NewValue = dbEntry.CurrentValues.GetValue<object>(propertyName) == null ? null : dbEntry.CurrentValues.GetValue<object>(propertyName).ToString()
                        }
                            );
                    }
                }
            }
            // Otherwise, don't do anything, we don't care about Unchanged or Detached entities
            return result;
        }

在修改的部分,我有以下代码行

  var doNotAUditDefined = dbEntry.Property(propertyName).GetType().GetCustomAttributes(typeof(DoNotAudit), false);

当我逐步完成代码时,即使对于 modifiedDate 属性,这也显示为空。 这怎么可能? 任何帮助不胜感激

谢谢

使用以下代码得到什么:

dbEntry.Property(propertyName).GetType()

是修改属性的类型,如 ModifiedType 的情况下的 DateTime? 。因此,DateTime?类上没有定义任何属性。 (因为该属性是在AuditZone类中定义的)

我要做的是在进入审计代码的修改部分之前保存不应审核的属性列表(至少在循环修改的属性列表之前)。然后,在循环遍历修改的属性时,检查属性名称是否在从审核中排除的属性列表中。像这样:

var auditExcludedProps = dbEntry.Entity.GetType()
                                       .GetProperties()
                                       .Where(p => p.GetCustomAttributes(typeof(DoNotAudit), false).Any())
                                       .Select(p => p.Name)
                                       .ToList();
foreach (string propertyName in dbEntry.OriginalValues.PropertyNames)
{
    var doNotAUditDefined = auditExcludedProps.Contains(propertyName);
    ...
}

您可能需要仔细检查dbEntry.Entity.GetType()是否返回您的类AuditZone,并且列表 auditExcludedProps 包含 ModifiedDate 属性。

希望对您有所帮助!

最新更新