Entity Framework: seguimiento de cambios en asociaciones FK

Estoy anulando SaveChanges en mi DbContext para implementar un registro de auditoría. Trabajar con relaciones de muchos a muchos o asociaciones independientes es relativamente fácil, ya que EF crea ObjectStateEntries para cualquier cambio en ese tipo de relaciones.

Estoy usando asociaciones de claves externas, y cuando una relación entre entidades cambia todo lo que obtienes es un ObjectStateEnty que dice, por ejemplo, que la entidad "Título" ha cambiado la propiedad "PublisherID". Para un humano, esta es obviamente una clave foránea en la entidad Título, pero ¿cómo puedo determinar esto en tiempo de ejecución? ¿Hay alguna manera de traducir este cambio a una propiedad "PublisherID" para que una EntityKey para la entidad que representa la clave externa?

Supongo que estoy tratando con entidades que se ven así:

public sealed class Publisher
{
    public Guid ID { get; set; }
    public string Name { get; set; }
    public ICollection<Title> Titles { get; set; }
}

public class Title
{
    public Guid ID { get; set; }
    public string Name { get; set; }
    public Guid? PublisherID { get; set; }
    public Publisher Publisher { get; set; }
}

También hay un código de EF EntityConfiguration que define la relación y la clave externa:

public TitleConfiguration()
{
    HasOptional<Publisher>(t => t.Publisher).WithMany(
            p => p.Titles).HasForeignKey(t => t.PublisherID);
}

Lo que estoy haciendo ahora parece demasiado complicado. Espero que haya una forma más elegante de lograr mi objetivo. Para cada propiedad modificada de ObjectStateEntry, miro a través de todas las ReferentialConstraints para la entidad actual y veo si alguna de ellas la usa como una clave foránea. El código siguiente se llama desde SaveChanges ():

private void HandleProperties(ObjectStateEntry entry, 
        ObjectContext ctx)
{
    string[] changedProperties = entry.GetModifiedProperties().ToArray();
    foreach (string propertyName in changedProperties)
    {
        HandleForeignKey(entry, ctx, propertyName);
    }
}

private void HandleForeignKey(ObjectStateEntry entry, 
        ObjectContext ctx, string propertyName)
{
    IEnumerable<IRelatedEnd> relatedEnds = 
            entry.RelationshipManager.GetAllRelatedEnds();

    foreach (IRelatedEnd end in relatedEnds)
    {
        // find foreign key relationships
        AssociationType elementType = end.RelationshipSet.ElementType as 
                AssociationType;
        if (elementType == null || !elementType.IsForeignKey) continue;

        foreach (ReferentialConstraint constraint in 
                elementType.ReferentialConstraints)
        {
            // Multiplicity many means we are looking at a foreign key in a 
            // dependent entity
            // I assume that ToRole will point to a dependent entity, don't 
            // know if it can be FromRole
            Debug.Assert(constraint.ToRole.RelationshipMultiplicity == 
                    RelationshipMultiplicity.Many);
            // If not 1 then it is a composite key I guess. 
            // Becomes a lot more difficult to handle.
            Debug.Assert(constraint.ToProperties.Count == 1);
            EdmProperty prop = constraint.ToProperties[0];

            // entity types of current entity and foreign key entity 
            // must be the same
            if (prop.DeclaringType == entry.EntitySet.ElementType 
                    && propertyName == prop.Name)
            {
                EntityReference principalEntity = end as EntityReference;
                if (principalEntity == null) continue;

                EntityKey newEntity = principalEntity.EntityKey;
                // if there is more than one, the foreign key is composite
                Debug.Assert(newEntity.EntityKeyValues.Length == 1);

                // create an EntityKey for the old foreign key value
                EntityKey oldEntity = null;

                if (entry.OriginalValues[prop.Name] is DBNull)
                {
                    oldEntity = new EntityKey();
                    oldEntity.EntityKeyValues = new[] { 
                        new EntityKeyMember("ID", "NULL") 
                    };
                    oldEntity.EntitySetName = newEntity.EntitySetName;
                }
                else
                {
                    Guid oldGuid = Guid.Parse(
                            entry.OriginalValues[prop.Name].ToString());
                    oldEntity = ctx.CreateEntityKey(newEntity.EntitySetName, 
                            new Publisher()
                            {
                                ID = oldGuid
                            });
                }

                Debug.WriteLine(
                        "Foreign key {0} changed from [{1}: {2}] to [{3}: {4}]", 
                        prop.Name,
                        oldEntity.EntitySetName, oldEntity.EntityKeyValues[0],
                        newEntity.EntitySetName, newEntity.EntityKeyValues[0]);
            }
        }
    }
}

Espero que esto ayude a ilustrar mejor lo que estoy tratando de lograr. Cualquier entrada es bienvenida.

¡Gracias

Respuestas a la pregunta(1)

Su respuesta a la pregunta