Is there a better/cleaner way to find Independent Association changes (adds/removes) than this?

女生的网名这么多〃 提交于 2020-01-13 19:10:40

问题


I found this answer which (unless I'm missing something) gives a good solution to catch all changes made to all independent associations in a DbContext. I am trying to adapt that solution to something more specific, to create a function that can find the changes for a particular navigation property on a particular entity. The goal is for the user of this function to not have to worry about any of the internals of EntityFramework, and to only be concerned with his POCO models.

This is what I have so far, and it works. But to my eye it looks very messy and prone to break if internal implementation details of Entity Framework change--particularly there's a "magic string" "ClrPropertyInfo" in there that may not be intended as part of the EF interface contract.

public partial class EntityFrameworkMaterializer
{
    public IEnumerable<T2> GetAssociationChanges<T1,T2>(T1 parent, string propertyName, EntityState findState)
    {
        // this.context is a DbContext instance that is a property of the object.
        ObjectContext ocontext = ((IObjectContextAdapter)this.context).ObjectContext;
        MetadataWorkspace metadataWorkspace = ocontext.MetadataWorkspace;

        // Find the AssociationType that matches the property traits given as input            
        AssociationType atype =
            metadataWorkspace.GetItems<AssociationType>(DataSpace.CSpace)
            .Where(a => a.AssociationEndMembers.Any(
                ae => ae.MetadataProperties.Any(mp => mp.Name == "ClrPropertyInfo" // Magic string!!!
                    && ((PropertyInfo)mp.Value).Name == propertyName
                    && typeof(T1).IsAssignableFrom(((PropertyInfo)mp.Value).DeclaringType)
                    )
                    )
                    ).First();

        // Find added or deleted DbDataRecords from the above discovered type
        ocontext.DetectChanges();
        IEnumerable<DbDataRecord> dbDataRecords = ocontext.ObjectStateManager
            .GetObjectStateEntries(findState)
            .Where(e => e.IsRelationship)
            // Oddly, this works, while doing the same thing below requires comparing .Name...?
            .Where(e => e.EntitySet.ElementType == atype)
            .Select(e => findState == EntityState.Deleted ? e.OriginalValues : e.CurrentValues);

        // Get the actual entities using the EntityKeys in the DbDataRecord
        IList<T2> relationChanges = new List<T2>();
        foreach (System.Data.Common.DbDataRecord ddr in dbDataRecords)
        {
            EntityKey ek = (EntityKey)ddr[0];
            // Comparing .ElementType to atype doesn't work, see above...?
            if (!(ek.GetEntitySet(metadataWorkspace).ElementType.Name == atype.Name))
            {
                ek = (EntityKey)ddr[1];
            }
            relationChanges.Add((T2)ocontext.GetObjectByKey(ek));
        }
        return relationChanges;
    }
}

Example of usage:

// Student <--> Course is many-to-many Independent Association
IEnumerable<Course> droppedCourses;
droppedCourses = GetAssociationChanges<Student, Course>(
    student,
    "EnrolledCourses",
    EntityState.Deleted
);

This was the result of a LOT of reverse-engineering and digging around through objects in the debugger. Besides the magic string problem, I wonder if there is a more direct path to figuring out the type of the "relationship entries" representing the IAs based on the "end" entity type and the navigation property name.

来源:https://stackoverflow.com/questions/25400882/is-there-a-better-cleaner-way-to-find-independent-association-changes-adds-remo

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!