title: Entity Framework: Tracking changes to independent associations
body: <p>Entity framework makes it easy to track changes to relationships between two entities. The following will return ObjectStateEntry instances for all added and deleted relationships:</p>
  
  <pre><code>ObjectStateManager.GetObjectStateEntries(
                  EntityState.Added | EntityState.Deleted)
                  .Where(e =&gt; e.IsRelationship);
  </code></pre>
  
  <p>For audit purposes I want to retrieve the following information about each association end:</p>
  
  <ul>
  <li>navigation property name (if any)</li>
  <li>multiplicity</li>
  </ul>
  
  <p>For added associations ObjectStateEntry instance contains EntityKey objects for both entities involved in the relationship:</p>
  
  <pre><code>var key0 = entry.CurrentValues[0] as EntityKey;
  var key1 = entry.CurrentValues[1] as EntityKey;
  </code></pre>
  
  <p>It also references the type that represents current relationships:</p>
  
  <pre><code>var relationshipType = objectStateEntry.EntitySet.ElementType;
  </code></pre>
  
  <p>What I am trying to do is map each entity key (key0, key1) to the appropriate ends of association (relationshipType.KeyMembers). The only way to do this as far as I can tell is to look at the referenced type of each association end and match it with the type of the entity represented by an entity key. However, this will not work if the both ends of an association reference the same entity type (think employee entity with manager FK that references another employee).</p>
  
  <p>So here are helper functions that I got so far to get navigation property name and multiplicity of a relationship end. Is there a better way to do the same?</p>
  
  <pre><code>public static string GetNavigationPropertyName(
          this ObjectStateEntry entry, EntityKey key)
  {
      var relationshipType = entry.EntitySet.ElementType;
      var entitySet = key.GetEntitySet(
              entry.ObjectStateManager.MetadataWorkspace);
      var property = entitySet.ElementType.NavigationProperties.Where(
              p =&gt; p.RelationshipType == relationshipType)
              .SingleOrDefault();
  
      if (property == null)
      {
          return null;
      }
  
      return property.Name;
  }
  
  public static RelationshipMultiplicity GetAssociationEndMultiplicity(
          this ObjectStateEntry entry, EntityKey key)
  {
      var relationshipType = entry.EntitySet.ElementType;
  
      var entitySet = key.GetEntitySet(
              entry.ObjectStateManager.MetadataWorkspace);
  
      foreach (EdmMember member in relationshipType.KeyMembers)
      {
          var refType = member.TypeUsage.EdmType as RefType;
          if (refType.ElementType == entitySet.ElementType)
          {
              var relEndMember = member as RelationshipEndMember;
              return relEndMember.RelationshipMultiplicity;
          }
      }
      throw new InvalidOperationException(
              "couldn't find association end");
  }
  </code></pre>
  
  <p>Any suggestions/ideas are welcome.</p>
  
  <p>Thanks,
  Daniel</p>