I have an Entity Framework Code First DbContext with the following entities configured. In this example class Bar is a child of class Foo.
public class Foo
{
I was actually able to determine the foreign key properties by using the GetDependentProperties method of the NavigationProperty class.
Here is the code that I used (more or less) to get what I needed:
object[] GetForeignKeyPropertyValues(TEntity entity, Expression> navigationProperty)
{
if (entity == null)
return new object[] { };
// Find the entity metadata in the object context.
// (Assume you have access to the DbContext through the property CurrentDbContext.)
var objectContext = (CurrentDbContext as IObjectContextAdapter).ObjectContext;
var metadataNamespace = ObjectContextAdapter.GetType().Namespace;
var entityIdentity = metadataNamespace + "." + typeof(TEntity).Name; // HACK: This seems to work to retrieve the EntityType for an entity.
var entityMetadata = objectContext.MetadataWorkspace.GetItem(entityIdentity, DataSpace.CSpace);
// TODO: Verify that the entity metadata was found.
// Get the navigation property metadata by parsing the name from the navigation property expression.
var navigationPropertyName = GetPropertyName(navigationProperty);
var navigationPropertyMetadata = entityMetadata.NavigationProperties.FirstOrDefault(np => np.Name == navigationPropertyName);
// TODO: (JMB) Verify that the navigation property metadata was found.
// Extract the foreign key columns from the navigation property.
var foreignKeyPropertyMetadatas = navigationPropertyMetadata.GetDependentProperties();
// Create property getters for each foreign key property.
var foreignKeyPropertyGetters = foreignKeyPropertyMetadatas
.Select(propertyMetadata => MakePropertyGetter(propertyMetadata.Name))
.ToArray();
// Execute the foreign key property getters to get the foreign key property values for the specified entity.
var foreignKeyPropertyValues = foreignKeyPropertyGetters
.Select(propertyGetter => propertyGetter(entity))
.ToArray();
return foreignKeyPropertyValues;
}
static string GetPropertyName(Expression> navigationProperty)
{
var lambda = navigationProperty as LambdaExpression;
var member = lambda.Body as MemberExpression;
return member.Member.Name;
}
static Func MakePropertyGetter(Type entityType, string propertyName)
{
var parameterExpression = Expression.Parameter(typeof(TEntity), "entity");
var propertyExpression = Expression.PropertyOrField(parameterExpression, propertyName);
var lambdaExpression = Expression.Lambda(propertyExpression, parameterExpression);
var lambdaFunction = lambdaExpression.Compile();
return (Func)lambdaFunction;
}