jeudi 17 mars 2016

EF6 Changed Properties With a Certain Attribute

I've been playing around with auto-auditing on an EF6 code-first architecture.

I'm having a little trouble getting the right combination of things working.

Let's say I have a custom attribute, named AuditableAttribute:

[AttributeUsage(AttributeTargets.Property)]
public class AuditableAttribute : System.Attribute
{
    public AuditableAttribute()
    {

    }
}

and I've applied it to some properties on my EF POCOs, as such:

[Table("Regions")]
public class Region : BaseAuditable
{
    [Key,
        DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int RegionId { get; set; }

    [Required,
        StringLength(128),
        Auditable]
    public string Name { get; set; }
}

and:

public abstract class BaseAuditable : Base, IAuditable
{
    public string CreatedBy { get; set; }
    public string UpdatedBy { get; set; }

    public DateTime DateCreated { get; set; }
    public DateTime DateUpdated { get; set; }
}

public abstract class Base
{
    [Required,
        StringLength(128)]
    public string GlobalId { get; set; }

    public Base(string uniqueIdentifier)
    {
        GlobalId = uniqueIdentifier;
    }

    public Base(Guid uniqueIdentifier) : this(uniqueIdentifier.ToString())
    {
    }

    public Base() : this(Guid.NewGuid().ToString())
    {
    }
}

In my DbContext.SaveChanges(), I've tried a number of things, but they all seem to work against each other.

For example, I wanted to get all of the Entities that implement the IAuditable interface like this:

var changeSet = ChangeTracker.Entries<IAuditable>();

This works, but in my foreach(var entry in changeset), the entry is of type IAuditable. I can't quite seem to figure out what the actual generic type of the object is (and even if I found it, I would have to cast to it) and therefore, I can't access the actual properties to which the Auditable attribute has been applied.

So, I can use:

var changeSet = ChangeTracker.Entries();

and then maybe something like

if (entry.Entity.GetType().GetInterface("IAuditable") == typeof(IAuditable))

but it still doesn't matter because I end up with something like this:

entry.OriginalValues.PropertyNames.ToList().ForEach(p =>
        {
            var propertyInfo = entry.GetType().GetProperty(p)
.GetCustomAttributes(typeof(AuditableAttribute), true).Cast<AuditableAttribute>()
.FirstOrDefault();
 // ...
      }

and, as you might expect, the GetType().GetProperty(p) is null because the object being evaluated is of type IAuditable, not the type that actually has the property in question.

So, here's my question: does anyone have a best practice for what I'm trying to do? I basically want to apply an attribute to particular properties and then check only those properties to see if they have been modified.

I'm open to other, radically different, suggestions about the structure of what I'm trying to do, which is to track the changes of particular fields.

Anyone know how to solve this one?





Aucun commentaire:

Enregistrer un commentaire